perm filename GOGOL[S,AIL]1 blob sn#000807 filedate 1972-10-13 generic text, type T, neo UTF8
COMMENT ⊗   VALID 00054 PAGES VERSION 16-2(49)
RECORD PAGE   DESCRIPTION
 00001 00001
 00005 00002	HISTORY
 00009 00003	Command File Descriptions
 00011 00004	Conditional Assembly Switches, Macros
 00015 00005	Titles, Versions
 00016 00006	AC Definitions
 00017 00007	CDB, SIMIO Indices For IOSER, OTHER INDICES
 00021 00008	Base (Low Segment) Data Descriptions -- Macros, Compil spec
 00023 00009	Base (Low Segment) Data Descriptions - Params, Links, Size specs
 00030 00010	Initialization Routines, Data
 00032 00011	Sailor, Reent --  Allocation, Main Program Control
 00035 00012	.SEG2. -- Get a second segment
 00038 00013	
 00041 00014	
 00044 00015	
 00045 00016	 Segment-Fetching Data
 00048 00017	
 00049 00018	 %ALLOC -- Main Allocation Routine
 00055 00019	
 00062 00020	
 00066 00021	
 00069 00022	  Utility Subroutines for allocation
 00071 00023	%UUOLNK -- UUO Handler (Dispatch Vector Just Below)
 00073 00024	 ILLUUO, PDLOV, ERR UUO Handlers
 00078 00025	
 00081 00026	  Special Printing Routines For Error Handler
 00084 00027	  Code to Handle Linkage to Editors
 00087 00028	
 00091 00029	 DECPNT, OCTPNT, FIX, FLOAT UUOs
 00093 00030	 DSPLIN, etc.for Disp. Text Line on Error (Compiler)
 00094 00031	SAVE, RESTR, INSET -- General Utility Routines
 00098 00032	Core Service Routines -- General Description
 00102 00033	 Special AC Declarations
 00103 00034	  Utility Routines
 00108 00035	
 00112 00036	 CORGET
 00116 00037	
 00118 00038	 CORINC, CANINC
 00123 00039	 CORREL
 00128 00040	 CORPRT, CORBIG
 00131 00041	String Garbage Collector Routines 
 00136 00042	
 00139 00043	
 00144 00044	
 00148 00045	
 00152 00046	
 00154 00047	
 00156 00048	
 00158 00049	Some Runtime Routines Which Could Go Nowhere Else
 00159 00050	 Kounter Routines
 00161 00051	
 00167 00052	
 00169 00053	
 00170 00054	
 00172 ENDMK
⊗;
COMMENT ⊗HISTORY
AUTHOR,FAIL,REASON
031  202000000061  ⊗;
DEFINE .VERSION <202000000061>

COMMENT ⊗
VERSION 16-2(49) 10-12-72 BY RHT ADD PPMAX FOR EXPO VERSION (NEEDED BY ED LNKG)
VERSION 16-2(48) 10-5-72 BY JRL MAKE GLUSER INTERNAL
VERSION 16-2(47) 10-3-72 BY RHT MAKE USER INIT WORK RIGHT
VERSION 16-2(46) 9-24-72 BY JRL FIX LIB ENTRIES FOR PROC. STR GAR COL
VERSION 16-2(45) 9-21-72 BY RHT SCREW UP THE COMPIL MACRO
VERSION 16-2(44) 9-21-72 BY JRL ADD SPRPDA TO SGC COMPIL MACRO
VERSION 16-2(43) 9-11-72 BY JRL ADD GINFTB,GDATM TO LOWER WHEN NO GLOB
VERSION 16-2(42) 9-5-72 BY JRL BAD FIX TO SGLKBK PROBLEM
VERSION 16-2(41) 8-21-72 BY RHT PUT IN JRL'S STACSV &STACRS
VERSION 16-2(40) 8-7-72 BY RHT CHANGE INILNK STUFF
VERSION 16-2(39) 8-7-72 BY KVL PRINT MSG BEFORE CANT CONTINUE ANY FURTHER MSG (P24)
VERSION 16-2(38) 7-3-72 BY DCS BUG #IC# ADD NEW MEANING TO NOSHRK(USER)
VERSION 16-2(37) 7-3-72 BY DCS BUG #IB# MAKE DEFAULT SYSTEM STACK SIZE BIGGER
VERSION 16-2(36) 7-2-72 BY JRL HAVE %ALLOC CALL LPINI IF NEEDED
VERSION 16-2(35) 6-20-72 BY DCS BUG #HU# BETTER TTY PRINTOUT
VERSION 16-2(34) 5-16-72 BY DCS BUG #HI# %ARRSRT TESTS RIGHT BIT FOR STR ARRAY NOW
VERSION 16-2(33) 5-11-72 BY DCS BUG #HE# MODIFY VERSION CHECKING, INSTALL VERSION 16
VERSION 15-6(23-32) 5-3-72 VARIOUS FIXES
VERSION 15-6(14-22) 2-21-72 VARIOUS FIXES
VERSION 15-6(13) 2-19-72 BY RHT THE BRAVE NEW WORLD
VERSION 15-2(12) 2-5-72 BY DCS BUG #GI# REMOVE TOPSTR
VERSION 15-2(11) 2-2-72 BY DCS BUG #GI# LEAVE SOME SLOP IN REMCHR SO CAT'LL BE MORE EFFICIENT
VERSION 15-2(10) 2-1-72 BY DCS REPLACE (FIXED) %ALLOC BLOCK ACCESSES BY SYMBOLIC HEAD-DEFINED ONES
VERSION 15-2(9) 1-30-72 BY DCS REPLACE %ALLOC -- INITIAL ALLOCATION
VERSION 15-2(8) 1-14-72 BY DCS BUG #GA# SEGMENTS HAVE .SEG EXTENSIONS, NOT .REL
VERSION 15-2(7) 1-3-72 BY DCS BUG #FX# REMOVE NEED FOR COM2, REORGANIZE SEGMENT-GETTING STUFF
VERSION 15-2(6) 12-26-71 BY DCS BUG #FU# REENABLE ACCESS FROM ERR UUO TO FTDEBUGGER
VERSION 15-2(5) 12-24-71 BY DCS BUG #FT# DSPLIN BETTER, TV AS VALID EDITOR
VERSION 15-2(4) 12-22-71 BY DCS BUG #FF# SIXPRT(14-15) TO ERR, IOERR ROUTS
VERSION 15-2(3) 12-22-71 BY DCS BUG #FS# REMOVE SAILRUN, COM2, ASSUME COMPILER
VERSION 15-2(2) 12-2-71 BY DCS ADD VERSION SETUP CODE
VERSION 15-2(1) 12-2-71 BY DCS INSTALL VERSION NUMBER

⊗;
SUBTTL	Command File Descriptions
	LSTON	(GOGOL)
COMMENT ⊗

The following command files make runtime routines:

1.	RUN
	One assembly, get a non-library, non-2d-segment runtime package

RUNTIM=CALLIS(LR)+HEAD+ORDER+GOGOL+STRSER+IOSER+NWORLD+LEPRUN+MESPRO+WRDGET

2.	SGMNT
	Makes the non-global UPPER.REL and SAILOW.REL, which when
	loaded and run and stuff become SAISGn.SEG and SAILOW.REL,
	the 2d segment runtime routines

TAILOR=HEAD+FILSPC+TAILOR/NOLO
LOWER=CALLIS+HEAD+LOW+FILSPC+GOGOL/NOLO
TAILOR.REL,UPPER=CALLIS+HEAD+UP.FAI+ORDER+GOGOL+STRSER+IOSER+
          NWORLD+LEPRUN+MESPRO+WRDGET

5.	GSGMNT
	Makes the global model SAILOW AND UPPER, otherwise like
	 SGMNT

Same, but add GLB after HEAD in all three.

6.	SCISS.SAI
	This SAIL program, when run, uses the runtime files to
	 make a LIBSAI.REL file, the SAIL (lower-segment) library
⊗
SUBTTL	Conditional Assembly Switches, Macros
DSCR ** CONDITIONAL ASSEMBLY SWITCHES **
⊗

STSW(UPPER,0)		;NOT UPPER OR LOWER IF NEITHER SET
STSW(LOWER,0)
STSW(GLOBSW,0)		;ONLY GLOBAL IF SOMEBODY ELSE SAID SO
STSW(SEGS,0)
STSW(RENSW,0)		;RE-ENTRANT LIBRARY (HISEG) IF ON
STSW(LEAPSW,1)		;ASSUME LEAP

DSCR COMPIL(NAM,ENTRIES,EXTERNALS,DESCRIPTION,INTERNALS,HINHB)
CAL MACRO
PAR NAM IS 3 CHAR NAME -- TITLE WILL BE SAINAM
 ENTRIES ARE LIST OF ENTRIES CONTAINED IN THIS
  LIBRARY ASSEMBLY (INTERNALS IF NOT LIBRARY SETUP)
 EXTERNALS (OPTIONAL) ARE EXTERNALS NEEDED FOR THIS ENTRY.
 DESCRIPTION IS OPTIONAL, AND IS USED IN THE SUBTTL
  IF PRESENT.
 INTERNALS (OPTIONAL) DESCRIBE INTERNALS WHICH ARE NEVER ENTRIES.
 HINHB (OPTIONAL ANYTHING), IF NON-BLANK, INHIBITS THE HISEG)
DES IF MAKING A LIBRARY, AND IF THIS FILE IS DESIRED
  (SEE SCISS PROGRAM), A FILE OF THE NAME SAINAM.FAI
  WILL BE MADE CONTAINING ALL THE PROGRAM TEXT FROM THE
  COMPIL MACRO TO THE ENDCOM MACRO WHICH SHOULD FOLLOW
  THE CODE FOR THIS ENTRY.  ENDCOM DOES AN END IF
  IN LIBRARY COMPILE MODE.
RES THE MACRO EXPANDS TO PROVIDE A TITLE AND THE
  APPROPRIATE ENTRIES AND EXTERNALS FOR THIS ASSEMBLY.
  ALSO A SUBTTL CONTAINING THE TITLE AND OPTIONAL
  DESCRIPTION IS PROVIDED.
⊗
DEFINE COMPIL ' (NAM,ENT,EXT,DSCRP,INT,HINHB,DUMMY) <
IFIDN <DUMMY>,<> <
SUBTTL SAI'NAM -- DSCRP

IFE ALWAYS,<
	IFDIF <><ENT>,<ENTRY ENT>
	TITLE	SAI'NAM
REN <
	IFIDN <><HINHB>,<HISEG		;LOAD TO UPPER IF POSSIBLE>
>;REN
	IFDIF <><EXT>,<EXTERN EXT>
>;IFE ALWAYS
NOLOW <
	IFDIF <><INT>,<INTERN INT>
IFN ALWAYS,<
IFDIF <NAM><LOR>,<
IFDIF <><ENT>,<INTERNAL ENT>
>>
>;NOLOW
>;IFIDN <DUMMY>
>

DEFINE COMPXX ' (NAM,ENT,EXT,DSCRP,INT,HINHB) 
	<COMPIL(<NAM>,<ENT>,<EXT>,<DSCRP>,<INT>,<HINHB>)>

DEFINE ENDCOM (NAM) <
IFE ALWAYS,<
	END
>;IFE ALWAYS
>
; SWITCHES TO CONTROL LIBRARY COMPILATION

IFNDEF ALWAYS,<↓ALWAYS←←1>

IFN ALWAYS,<DEFINE ENTINT (X) <INTERNAL X>>
IFE ALWAYS,<DEFINE ENTINT (X) <ENTRY X>>

SUBTTL	Titles, Versions
DSCR  TITLES, VERSIONS
⊗
IFN ALWAYS,<
;  "TITLE	UPPER"	IS FOUND IN UP.FAI FILE TO MAKE OUTER PROG TITLED
LOW <
	TITLE LOWER
>;LOW
NOUP <
NOLOW <
	TITLE RUNTIM -- SAIL RUNTIME ROUTINES
>;NOLOW

JOBVER←←137
	LOC	JOBVER
;;#HE# DCS 5-11-72 (1-2) MODIFY VERSION STUFF
	.VERSION&777777000000	;CURRENT VERSION NUMBER (LH ONLY)
;;#HE# (1-2)
	RELOC
	LOC	124		;SET UP REENTER ADDRESS
	REENT
	RELOC
>;NOUP
>;ALWAYS≠0
EXTERNAL JOBHRL
SUBTTL	AC Definitions
DSCR  AC DEFINITIONS
⊗

; AC DEFINITIONS FOR SERVICE AND RUNTIME ROUTINES

; ALL	    UUO ROUTS,	    IOSER		COMMENTS
;	    CORE ROUTS,
;	    STRING GC,
;	    ALLOCATION

↓FF←←0
↓A←1						;TEMPS FOR ALLES
↓B←2						; (SOMETIMES SAVED)
↓C←3
↓D←4
		↓E←5		↓X←5		;MORE TEMPS
		↓Q1←6		↓Y←6
		↓Q2←7		↓Z←7
		↓Q3←10		↓Q←10
		↓T←11		↓CDB←11		;CHANNEL DATA BLOCK PTR
		↓T1←12		↓CHNL←12	;CHNL # FOR IOSER
↓LPSA←13					;TEMP, PARAM AC
↓TEMP←14					;TEMP ONLY
↓USER←15					;→USER TABLE FOR RNTRNT ROUTS
↓SP←16						;STRING STACK
↓P←17						;SYSTEM STACK
SUBTTL	CDB, SIMIO Indices For IOSER, OTHER INDICES

DSCR -- CDB, SIMIO INDICES FOR IOSER
DES The I/O routines obtain their information from the user via a
  channel number -- the same kind used by the system. In order to
  find byte pointers, counts, file names, etc., the channel number is
  used to index into a block of core called a CDB (Channel Data Block).
  This CDB is filled with good data during the OPEN operation.
 The CDB, and all I/O buffers, are obtained from CORGET.
 The CHANS table in the GOGTAB area is a 20 word block containing
  pointers to the appropriate CDB's.
 Since channel numbers must appear in the AC field of IO instructions,
  one must construct IO insts. in impure places to retain re-entrancy.
  XCT INDEX,SIMIO executes the appropriate IO instruction with the
  channel number from AC CHNL, used by all routines.  See SIMIO for
  operational details.
⊗

;  SIMIO INDICES		        FORMAT OF CDBs

DMODE	←← 0	    ↔↓IOSTATUS ←← 0	;DATA MODE		;RETURN STATUS
DNAME	←← 1	    ↔↓IOIN     ←← 1	;DEVICE			;BUFFERED INPUT
BFHED	←← 2	    ↔↓IODIN    ←← 2	;HEADER POINTERS	;DUMP INPUT
		     ↓IOOUT    ←← 3     			;BUFMODE OUT.
OBPNT	←← 3	    ↔↓IODOUT   ←← 4	;OUTPUT BUF. PTR	;DUMP OUTPUT
OBP	←← 4	    ↔↓IOCLOSE  ←← 5	;OUTPUT BYTE PTR	;CLOSE FILE
OCOWNT	←← 5	    ↔↓IORELEASE←← 6	;OUTPUT BYTE CNT	;RELEASE FILE
ONAME	←← 6	    ↔↓IOINBUF  ←← 7	;OUTPUT FILE NAM	;INBUF
OBUF	←← 7	    ↔↓IOOUTBUF ←←10	;OUTPUT BUFFER LOC.	;OUTBUF
		    ↔↓IOSETI   ←←11				;USETI
IBPNT	←←10	    ↔↓IOSETO   ←←12	;SAME FOR INPUT		;USETO
IBP	←←11	    ↔						;  13 UNUSED
ICOWNT	←←12	    ↔↓IOOPEN   ←←14				;OPEN CHANNEL
INAME	←←13	    ↔↓IOLOOKUP ←←15				;LOOKUP FILE
IBUF	←←14	    ↔↓IOENTER  ←←16				;ENTER FILE
		    ↔↓IORENAME ←←17				;RENAME FILE

ICOUNT	←←15	;INPUT DATA COUNT LIMIT ADDRESS
BRCHAR	←←16	;XWD TTYDEV FLAG, INPUT BREAK CHAR ADDR
TTYDEV  ←←16	;LH -1 IF DEVICE IS A TTY -- USED BY OUT
ENDFL	←←17	;INPUT END OF FILE FLAG ADDR
ERRTST	←←20	;USER ERROR BITS SPECIFICATION WORD
PGNNO	←←20	;PAGE NUMBER FOR DISPLAY FEATURE (IF FEATURE NOT INCLUDED)
NOEXPO <
PGNNO	←←21	;SAME THING IF IT IS INCLUDED
>;NOEXPO
↑IOTLEN	←←PGNNO+1	;LENGTH OF TABLE ENTRY

↓LUPDL←30			;LENGTH OF UUO PDL
↓MINPDS←←=64			;SMALLEST ALLOWABLE SYSTEM PDL SIZE
↓DEFPDS←←=192			;DEFAULT PDL SIZE
SUBTTL	Base (Low Segment) Data Descriptions -- Macros, Compil spec

DSCR DATA DESCRIPTIONS, TAILORED FOR TWO SEGMENT OPERATION
⊗

NOUP <
DEFINE SGLK (ROUT,NAM,INT) <
 XX	(NAM,ROUT,INT)	;NAME OF STRING DSCRPTR GENERATING ROUTINE
 XX	(,0,)		;PLACE TO PUT A LINK
 LINK	%SGROT,.-1	;WHEREWITHAL TO GENERATE SAID LINK
>
>;NOUP
UP <
DEFINE SGLK (ROUT,NAM) <
 XX	(NAM,ROUT,)
 XX	(,0,)
>
>;UP

DEFINE XX  (A,B,C,D) <
	IFDIF <A><>,<↓ A :> B
	IFDIF <C><>,< C A >>>
UP <
III←←140
	DEFINE XX (A,B,C,D) <
	IFDIF <A><>,<↓ A ← III >
	III ←← III + 1
	IFDIF <D><>,<III←III+D-1>
>
>;UP


COMPIL(LOR,<SAILOR,.SEG2.>
	    ,<%UUOLNK,%ALLOC,%SPGC,%STRMRK,%ARRSRT,K.OUT,K.ZERO>
	    ,<BASE DATA, INITIALIZATION CONTROL>
	    ,<X11,X22,X33,X44>,INHIBIT)
SUBTTL	Base (Low Segment) Data Descriptions - Params, Links, Size specs

; UNIVERSAL VARIABLES -- BASES OF MAJOR DATA STRUCTURES, GLOBAL FLAGS

XX	(GOGTAB,0,INTERNAL)	;→USER TABLE
XX	(DATM,0,INTERNAL)	;XWD 3,→DATUM TABLE
XX	(LKSTAT,0,INTERNAL)	;STATUS OF GLOBAL LEAP MODEL INTERLOCK (SHOULD BE IN GOGTAB
XX	(INFTB,0,INTERNAL)	;XWD 2,→INFOTAB TABLE
XX	(.SKIP.,0,INTERNAL)	;RECORD AUX RESULTS OF RUNTIMES
XX	(RPGSW,0,INTERNAL)	;SET IF (JOBSA)+1 USED TO START
XX	(%RENSW,0,INTERNAL)	;SET IF USER REENTERS TO SPECIFY ALLOC
XX	(CONFIG,0,INTERNAL)	;0 FOR RUNTIME, <0 FOR COMPILER
XX	(ERRSPC,0,INTERNAL)	;ADDR OF COMPILER'S ERROR AUGMENTOR
XX	(RUNNER,0,INTERNAL)	;THE CURRENTLY RUNNING PROCESS(IF HAVE THEM)
XX	(INTRPT,0,INTERNAL)	;MASK FOR INTERRUPT POLLING
XX	(S1PARE,0)		;SPARE LOWER LOCATIONS
XX	(S2PARE,0)
XX	(S3PARE,0)
XX	(S4PARE,0)
XX	(S5PARE,0)
GLOB <
XX	(GSPARE,0)
>;GLOB
NOGLOB <
XX	(GDATM,0,INTERNAL)	;DUMMY GLOBAL DATUM TABLE SHOULD ALWAYS BE ZERO
GINFTB←GDATM			;DUMMY GLOBAL INFOTAB DITTO
	INTERNAL GINFTB
>;NOGLOB

; STATIC LINKAGES -- FEATURE PROVIDED BY LOADER
; THESE ARE THE BASES OF ONE-WAY LINKED LISTS WHICH ALLOW ACCESS
; TO SELECTED DATA IN ALL LOADED MODULES

XX	(STLNK,0,INTERNAL)	;1 ALL STRINGS TIED TOGETHER FOR STRNGC
XX	(SPLNEK,0,INTERNAL)	;2 ALL SPACE REQUESTS (PDLS, ETC.)
XX	(SETLET,0,INTERNAL)	;3 ALL SET VARIABLES TIED TOGETHER
XX	(SGROT,0,INTERNAL)	;4 LIST OF STRNGC SORTER GENERATORS
XX	(KTLNK,0,INTERNAL)	;5 ALL COUNTER BLOCKS
XX	(INILNK,0,INTERNAL)	;  INITIALIZATION ROUTINES (LPINI ONLY NOW)

 SYSPHS←←2			;TWO SYSTEM PHASES
 USRPHS←←1			;TWO USER PHASES (FOR NOW)

; THESE OPS INFORM THE LOADER OF THE ABOVE BASE LOCATIONS.

NOUP <
	LINKEND %STLNK,STLNK
	LINKEND	%SPLNK,SPLNEK
	LINKEND	%SETLK,SETLET
	LINKEND	%SGROT,SGROT
	LINKEND	%KTLNK,KTLNK
	LINKEND %INLNK,INILNK
>;NOUP

; SOME ROUTINES WHICH GO ON THE SGROT LIST (SEE SGLK)
;↑SGLKBK
SGLK	(%ARRSRT,SGLKBK,INTERNAL);ROUTINE TO COLLECT STRING ARRAYS
SGLK	(%STRMRK)		;ROUTINE TO COLLECT STRING VARIABLES
SGLK	(%SPGC)			;ROUTINE TO COLLECT STRING STACK


;HERE IS THE LIST OF DEFAULT SPACE ALLOCATION ENTRIES
XX	(%SPL,<BLOCK $SPREQ-2>,INTERNAL,$SPREQ-2);DUMMY FIXED ADDR STUFF
XX	(%STDLST,<BLOCK 2>,INTERNAL,2) 	 ;BASE OF BUILT-IN REQUESTS
XX	(,<XWD WNTPDP!MINSZ!USRTB,DEFPDS>) ;SYSTEM_PDL (SPECIAL, SEE BELOW)
XX	(,<XWD	[ASCIZ /SYSTEM_PDL/],PDL>)
XX	(,<XWD	WNTPDP!USRTB!MINSZ,50>)	 ;STRING STACK
XX	(,<XWD	[ASCIZ /STRING_PDL/],SPDL>)
XX	(,<XWD	WNTADR!WNTEND!USRTB!MINSZ,2000>);STRING_SPACE
XX	(,<XWD	[ASCIZ /STRING_SPACE/],ST>)
XX	(,0)			;THAT'S ALL
;	LINK	%SPLNK,%SPL	;%ALLOC DOES THIS EXPLICITLY SO THIS
				;BLOCK WILL BE FIRST

;SOME RANDOM GLOBALLY USEFUL THINGS, WHICH UNFORTUNATELY HAVE TO
;BE IN FIXED LOCATIONS (FOR THE RUNTIMES TO FIND)

XX	(ALLPDP,<IOWD 20,ALLPDL>,INTERNAL);USED FOR A WHILE DURING ALLOC
XX	(ALLPDL,<BLOCK 20>,INTERNAL,20)	  ;AND IN PROCESS TERMINATION
XX	(%ALLCHR,0,INTERNAL)
XX	(%OCTRET,0,INTERNAL)
XX	(%ERGO,0,INTERNAL)	;ON IF LF TYPED TO ERR. GUY
XX	(%RECOV,0,INTERNAL)	;ON IF RECOVERY FROM ERR. IS POSSIBLE
XX	(DPYSW,0,INTERNAL)	;ON IF CONSOLE IS DPY
XX	(%UACS,<BLOCK 20>,INTERNAL,20) ;UUOCON ACS
XX	(%UPDL,<BLOCK LUPDL+1>,INTERNAL,LUPDL+1) ;UUOCON PDL
NOEXPO <
XX	(PGDS,<PGDS0>,INTERNAL)	;PIECE OF GLASS FOR LINE BREAK ON INPUT
XX	(,7,)
XX	(PGDS0,0,)
XX	(,<AIVECT (300,200)>,)
XX	(,<ASCID /PAGE/>,)
XX	(,<ASCID /     />,)
XX	(,<ASCID /LINE />,)
XX	(,<ASCID /     />,)
XX	(,<DPYJMP PGDS0>,)
>;NOEXPO

;SOME WONDERFULLY USEFUL CONSTANTS

XX	(X11,<XWD 1,1>,INTERNAL)
XX	(X22,<XWD 2,2>,INTERNAL)
XX	(X33,<XWD 3,3>,INTERNAL)
XX	(X44,<XWD 4,4>,INTERNAL)

;SINCE UUO TRIGGERING IS NON-RE-ENTRANT, THIS IS THE PLACE WHERE IT HAPPENS

XX	(UUO0,0,INTERNAL)		;JSR RETURN STORED HERE
	↓UUCOR←UUO0
NOUP <
	JRST	%UUOLNK			;GO HANDLE UUO
>;NOUP

LOW <
	EXTERNAL LPINI
LPLK:	0
	LPINI
	0
LINK %INLNK,LPLK
>;LOW

EXPO <
XX	(PPMAX,<BLOCK 3>,INTERNAL,3)	;FOR SCREWY EDITOR LINKAGE
>;EXPO

SUBTTL	Initialization Routines, Data

COMMENT ⊗ The Run-Time I/O handling routines are re-entrant. This
 means that any modifiable words or parameters particular to a given
 user must come from the user's core image.  The pointer to this area
 will be found in GOGTAB in the lower segment.  The I/O routines use
 some of the AC'S in standard ways, described above with AC definitions.
⊗

DSCR SAILOR -- ALLOCATION AND INITIALIZATION ROUTINES
CAL JSR
DES

 Part of this is not yet reentrant. In particular,
	it is called by a JSR SAILOR
 The functions of this routine are:

1. Get a second segment, if this is a SAISEG-program
2. Process space requests, allow user-override if REENTER used
   to start.
3. Use %ALLOC to allocate requested regions.
4. Clear Kounters
5. Change starting and re-entry addresses,
6. PUSHJ to user program
7. Record Kounters, RESET and quit.
⊗
SUBTTL Sailor, Reent --  Allocation, Main Program Control

NOUP <
;SAIL job calls SAILOR first time, with RPGSW set up already

INTERNAL SAILOR
↑SAILOR: 0			;JSR to SAILOR
	JRST	FRSTRT		;GET A SEGMENT, START UP

; REENTER to manually change allocation, and to flush REQUIREd segments

↑REENT:	SETOM	%RENSW		;RE-ENTER -- ASK FOR NEW ALLOC

;SAIL STARTS HERE WHEN USER TYPES S<T<A<R<T>>>> AGAIN

↑RESTRT:TDZA	TEMP,TEMP	;ESTABLISH OPERATING MODE
	MOVNI	TEMP,1		;RPG MODE
	MOVEM	TEMP,RPGSW	;RECORD IT
FRSTRT:	JSP	P,.SEG2.	;GET SECOND SEGMENT

STRT:	CALLI
	SETZM	GOGTAB		;FORCE CORSER RE-INITIALIZATION
	SETNIT			;GET TEMP STACK, IF NECESSARY
	JSP	16,%ALLOC	;ALLOCATE AREAS
	MOVEI	A,RESTRT	;CHANGE JOBSA AND JOBREN
	HRRM	A,JOBSA		;"S" USES OLD ALLOCATION
	MOVEI	A,REENT		;"REE" ASKS QUESTIONS AGAIN
	MOVEM	A,JOBREN
	PUSHJ	P,K.ZERO	;ZERO OUT THE COUNTERS
	PUSHJ	P,INILST	;GO DO ALL OTHER INITIALIZATIONS
	PUSHJ	P,@SAILOR	;CALL USER PROGRAM
	PUSHJ	P,K.OUT		;WRITE OUT THE COUNTERS
	TERPRI	<END OF SAIL EXECUTION>
	CALL6	(0,RESET)	;CLEAR THE I/O WORLD
	CALL6	(1,EXIT)	;QUIT QUIETLY

INILST:	
	SKIPN	TEMP,INILNK
	POPJ	P,
	MOVE	USER,GOGTAB	;JUST TO BE SURE
	SKIPA	A,[XWD -SYSPHS,0]	;XWD #SYS PHASES,0
DOPHS:	HRRZ	TEMP,INILNK	;LIST OF THEM
NXLNK:	
	PUSH	P,TEMP		;SAVE LINK
NXIN:	ADDI 	TEMP,1		;LOOK AT NNEXT ENTRY
	SKIPN	B,(TEMP)	;END OF LINK LIST
	JRST	NXIN.1		;YES
	HLRZ	C,B		;PHASE NUMBER OF THIS
	CAIE	C,(A)		;THIS PHASE
	JRST	NXIN		;NO
	PUSH	P,A
	PUSH	P,TEMP
	PUSH	P,USER
	PUSHJ	P,(B)
	POP	P,USER
	POP	P,TEMP
	POP	P,A
	JRST	NXIN		;GO DO NEXT IN THIS
NXIN.1:	POP	P,TEMP
	HRRZ	TEMP,(TEMP)
	JUMPN	TEMP,NXLNK
NXPHS:	AOBJN	A,DOPHS		;GO ON TO NEXT PHASE
	TRNE	A,400000	;WERE THESE USERS?
	POPJ	P,		;YES
	MOVE	A,[XWD -USRPHS,400000] ;DO USER PHASES
	JRST	DOPHS
SUBTTL	.SEG2. -- Get a second segment

COMMENT ⊗   Initialize the second segment, if there is none and if desired.
 This occurs when the program is first started. This is a dummy routine
 if not a SAISEG-program
⊗

INTERNAL .SEG2.
.SEG2.:
LOW <
	SKIPE	JOBHRL		;IS THERE A SEGMENT?
>;LOW
	 JRST	 (P)		; YES, GO AHEAD (OR ALWAYS, IF NOLOW)
>;NOUP

LOW <

COMMENT ⊗ Now, if global model, get segment specifications from space blocks
of compiled programs (via REQUIRE verbs in source code). 
Segment name business is ignored in EXPO version, since segment and file
names are always equivalent (philosophical differences).
⊗

SEGTR:				;TRY AGAIN
GLOB <

	SKIPN	%RENSW		;IS LINK-TABLE AND/OR PREVIOUSLY COLLECTED
				; INFORMATION INVALID??
	 JRST	 SEG3		;NO
	FOR II⊂(SEGDEV,SEGFIL,SEGPPN,NMSAV) <
	SETZM	II
>
	JRST	ASKEM		;CLEAR ALL NON-USER SPECIFIED INFO

SEG3:	SKIPN	B,SPLNEK	;A SPACE BLOCK AROUND??
	 JRST	 ASKEM		; NO
GSGLP:	SKIPE	A,$SGD(B)	;DEVICE REQUEST
	MOVEM	A,SEGDEV
	SKIPE	TEMP,$SGF(B)	;FILE NAME FOR UPPER SEGMENT
	MOVEM	TEMP,SEGFIL
	SKIPE	TEMP,$SGPP(B)	;PPN FOR SAME
	MOVEM	TEMP,SEGPPN
	SKIPE	TEMP,$SGNM(B)	;SEGMENT NAME (UNUSED IN EXPO VERSION)
	MOVEM	TEMP,NMSAV
	SKIPE	B,(B)		;GO DOWN LINKED LIST
	 JRST	 GSGLP		; UNTIL EMPTY
>;GLOB

COMMENT ⊗ If not enough information was supplied (global model only),
ask questions of user to obtain file names, etc.  Also (NOEXPO only),
try to ATTSEG to a segment of the desired name. In the EXPO version,
all this is combined in the GETSEG below.
⊗
NOEXPO <	;SEGMENT NAME NOT USEFUL TO EXPO SYSTEM
GLOB <
	SKIPE	A,NMSAV		;DID WE GET A SEGMENT?
	 JRST	 GOTEM		; YES, TRY TO LINK TO IT

ASKEM:	TERPRI	<SEGMENT LOGICAL NAME?>
	JSR	GGNAM		;GET A SEGMENT NAME.
GOTEM:	MOVEM	A,NMSAV
>;GLOB
NOGLOB <
	MOVE	A,[FILXXX]	;TRY TO FIND IT.
>;NOGLOB
	CALLI	A,400016	;ATTSEG.
	SKIPA			;NO LUCK
	JRST	(P)		;OK, DONE
	HRRZ	B,A		;GET FAILURE CODE.
	CAIE	B,1		;AMBIGUITY?
	JRST	GETSE		;NO -- GET THE SEGMENT.
	HLRZS	A
	CALLI	A,400016	;ATTSEG.
	JSP	A,ERSEG
	JRST	(P)		;OK, GOT IT
>;NOEXPO
EXPO <
ASKEM:				;MISPLACED LABEL
>;EXPO
GETSE:	CALLI
GLOB <
	SKIPE	A,SEGFIL	;WAS ONE "REQUIRE"D?
	 JRST	 THSFL		; YES, USE IT
	TERPRI	<SEGMENT FILE NAME?>
	MOVE	A,[FILXXX]	;DEFAULT
	JSR	GGNAM	
THSFL:	MOVEM	A,SEGFIL	;NAME OF SEGMENT.
THSFL1:	SKIPE	A,SEGDEV	;WAS A DEVICE REQUESTED?
	 JRST	 THSDV		; YES
	TERPRI	<DEVICE?>
	MOVE	A,[SGDEVC]	;DEFAULT DEVICE
	JSR	GGNAM
	MOVEM	A,SEGDEV
	CAMN	A,['DSK   ']	;ASK FOR PPN IF DISK
	SKIPE	SEGPPN		;AND PPN=0
	JRST	THSDV		;DON'T ASK, ALREADY THERE
	TERPRI	<PPN?>
	MOVE	A,[SGPPNN]	;DEFAULT PPN
	JSR	GGNAM
	MOVEM	A,SEGPPN
	JRST	THSFL1		;NOW HAVE A DEVICE
THSDV:	MOVEM	A,INTT
	MOVE	A,[XWD SEGDEV,DEVSEG]	;MOVE LOOKUP SPEC IN
	BLT	A,SEGNAM+3
>;GLOB
NOGLOB <
	SETZM	SEGNAM+2
	MOVE	TEMP,[SGPPNN]
	MOVEM	TEMP,SEGNAM+3	;SET UP PPN
	HLLZS	SEGNAM+1
>;NOGLOB

COMMENT ⊗ Now work is nearly done in EXPO system, but all sorts of hair 
remains otherwise.  In either case, now get segment in, get it into 2d 
segment, name it right

⊗
NOEXPO <
	INIT	1,17
INTT:	SGDEVC			;GO GET THE RAW SEGMENT
	0
	JSP	A,ERSEG
	LOOKUP	1,SEGNAM
	JSP	A,ERSEG
	MOVS	A,SEGNAM+3	;WORD COUNT
	HRLM	A,LIOD		;WORD COUNT FOR DUMP MODE.
	MOVNS	A
	HRRO	D,JOBREL	;FOR LATER
	HRRM	D,LIOD		;PLACE TO START DUMP MODE INPUT.
	ADD	A,JOBREL	;TO GET THE AMOUNT OF CORE NEEDED.
	CALLI	A,11		;CORE UUO ----
	JSP	A,ERSEG
LOP22:	INPUT	1,[LIOD: IOWD 200,%UPDL
		    0]
GLOB <
	TLZ	D,-1		;NO, MAKE IT WRITEABLE IF GLOBAL MODEL.
>;GLOB
IFN NOPROT,<
	TLZ	D,-1		;MAKE WRITEABLE IF REQUESTED TO
>;NOPROT≠0
	CALL	D,[SIXBIT/REMAP/]	;
	JSP	A,ERSEG
NOGLOB <
	MOVE	A,[FILXXX]
>;NOGLOB
GLOB <
	MOVE	A,NMSAV
>;GLOB
	CALLI	A,400036	;SETNM2
	JRST	[MOVEI	A,0
		 CALLI	A,400015	;CORE2
	 	 JSP	A,ERSEG
GLOB <
		 SETOM	%RENSW	;FORCE TTY RITUAL
>;GLOB
		 JRST	SEGTR]		;TRY AGAIN.
	CALLI
>;NOEXPO

EXPO <
	SETZM	SEGNAM+4		;CLEAR LAST TWO WORDS OF GETSEG BLOCK
	SETZM	SEGNAM+5
	MOVEI	A,DEVSEG		;GET READY
	MOVEM	P,SAVPP
	CALL	A,[SIXBIT /GETSEG/]	;GET THE SEGMENT
	 JSP	 A,ERSEG		; COULDN'T
	MOVE	P,SAVPP
; NO WAY TO RENAME 2D SEGMENT, SO DON'T WORRY ABOUT IT
>;EXPO

	JRST	(P)			;RETURN
>;LOW

EXPO <
NOUP <
INTERNAL TYPER.,OVPCWD,ERRMSG
;THESE ARE BECUSE OF LIB40 CHANGES
; MADE CAPRICIOUSLY BY DEC
TYPER.:
ERRMSG:
OVPCWD:	JFCL
	ERR	<SOME FORTRAN ROUTINE HAS SEEN FIT TO COMPLAIN
ABOUT YOUR STYLE.  COMPLAIN TO DEC THAT THEIR ERROR MESSAGE
PROCEDURE IS NOT SUFFICIENTLY GENERAL TO ALLOW GRACEFUL INTERFACE
WITH SAIL.>
>;NOUP
>;EXPO
SUBTTL	 Segment-Fetching Data

LOW <

NMSAV:	0			;SAVE LOGICAL SEGMENT NAME HERE
SEGDEV: 0			;SAVE UPPER SEGMENT DEVICE NAME HERE
SEGFIL:	0			;SAVE UPPER SEGMENT FILE NAME HERE
NOEXPO <
	SIXBIT /SEG/		;ALWAYS
>;NOEXPO
EXPO <
	SIXBIT	/SHR/		;DIFFERENT STROKES FOR ....
>;EXPO
	0
SEGPPN: 0			;SAVE UPPER SEGMENT PPN HERE

DEVSEG:	SGDEVC			;USED ONLY BY EXPO'S GETSEG
SEGNAM:	FILXXX
NOEXPO <
	SIXBIT/SEG/
>;NOEXPO
EXPO <
	SIXBIT /SHR/
>;EXPO
	0
	SGPPNN			;SPECIFIED PPN DEFAULT
EXPO <
	0 ↔0			;SIX WORD BLOCK FOR GETSEG
SAVPP:	0			;P SAVED HERE OVER GETSEG
>;EXPO
ERSEG:	TERPRI	<SAIL SEGMENT LOADING ERROR>
GLOB<
	SETOM	%RENSW		;FORCE TTY RITUAL
>;GLOB

	CALLI 12

GLOB <
GGNAM:	0
	TTCALL	4,C		;INCHWL.
	CAIE	C,15		;IF NOTHING SPECIFIED,
	MOVEI	A,0		; USE THE DEFAULT
	SKIPA	B,[POINT 6,A]
GGGO:	TTCALL	C		;GET CHAR
	CAIN	C,15
	JRST	[TTCALL C ↔ JRST @GGNAM]	;RETURN ON CR.
	CAILE	C,140
	SUBI	C,40		;CONVERT LOWER CASE.
	SUBI	C,40		; → SIXBIT
	IDPB	C,B		;SAVE IT.
	JRST	GGGO
>;GLOB
>;LOW
ENDCOM(LOR)
LOW <
	END
>;LOW
COMPIL(LUP,<%UUOLNK,%ALLOC,SAVE,RESTR,STACSV,STACRS,INSET>
	   ,<CORGET,STCLER,%RECOV,%UACS,GOGTAB,%UPDL,CONFIG,%ALLCHR>
	   ,<INITIALIZATION ROUTINES, UUO HANDLER, UTILITY ROUTINES>)
IFE ALWAYS,<
INTERNAL %ALLOC
; MORE EXTERNALS
EXTERNAL	ALLPDP,ERRSPC,SETLET,DPYSW,INILNK
EXTERNAL	%ERGO,SPLNEK,UUO0,%OCTRET
EXTERNAL	X11,X22,X44,CORINC,%STDLS,%RENSW,%SPL,KTLNK
>;IFE ALWAYS

NOLOW <			;PUT IN UPPER SEGMENT AND ALL THAT FOLLOWS....
UP <

;IF YOU CHANGE ANYTHING ABOVE THIS POINT, YOU WILL
;HAVE TO RELOAD.  THIS IS THE UPPER SEGMENT DISPATCH TABLE FOR
;INTERNAL SYMBOLS.

	USE	DSPCH		;A PC FOR VECTOR JRSTS
	USE
	BLOCK =180		;SPACE FOR THE JRSTS.
>;UP

SUBTTL	 %ALLOC -- Main Allocation Routine

DSCR %ALLOC
CAL JSP 16,%ALLOC
DES Processes space reqests, allocates the storage for stacks,
 string space, etc.  Sets certain universal environmental variables

 The SPLNEK list, created by the LOADER from compiled requests, contains
 REQUEST blocks.  Space requests begin at location $SPREQ within each
 block.  The entries consist of two-word entries, viz:

		   -----------------------------
 →- SPLNEK ptr -→ |		| →next block	| --→
		   -----------------------------
		  |				|
		  |    fixed LEAP allocation	|
		  |	     data		|
		  |				|
		  |	     ... 		|
		   -----------------------------
	$SPREQ:	  |OP1    |INDX	| SIZe request	|
		  |- - - - - - - - - - - - - - -|
 		  | TEXt addr   | RESult ADdRess| (if ¬STDSPC --
		   -----------------------------    see below)
		  |OP2 ...	|   etc.	|
		   -----------------------------
		  |   ... more ops ...		|
		   -----------------------------
		  |      0 terminates		|
		   -----------------------------

 OP is a 12-bit field (0:11), whose bits are interpreted as:
   0  STDSPC  if 1, get TEX,RESADR spec from standard entry
	      indexed by INDX field -- this is only a 1-word wntry.
   1  WNTADR  requests that the address of the allocated core be
	      returned in the specified RESADR field. RESADR is
	      then incremented.
   2  WNTEND  requests that the address of the first word not in the
	      allocated area be placed in RESADR field. RESADR bumped.
   3  WNTPDP  requests that a PDP computed from address and length be
	      returned in like manner.
   4  USRTB  indicates that the RESADRs are indices into the user
	      table -- (GOGTAB) should be added before use.
   5  MINSZ   indicates that the size specified here should be REPLACED
	      by the first subsequent non-zero request (not ADDED).
	      Default value for this area -- anything overrides.

 INDX is a 6-bit field (12:17) used if STDSPC to cause the address to be
   obtained from a spec (with its own OP and addr words) built into GOGOL.
   This allows push-down list, string space, etc., sizes to be requested by
   object modules without knowing the locations of their descriptors.
   The indices represent:
  1  SYSPD    System push-down list (P)
  2  SYSSPD   String push-down list (SP)
  3  STRSP    String space size.

 SIZ replaces any previous request with MINSZ on.  Otherwise, its value is
   added to an accumulated size for this address.  The final result will
   specify the size of the area.
  SIZ<0 causes current entry to be disregarded.

 TEX is the address of an ASCIZ string describing the use of the area.
   It is used when the user REENTERs to ask him how much space he wants.
   A non-zero value means that no overriding is possible for this area.

 These requests are accumulated on the stack in two-word entries as:
		   -----------------------------
	$SPREQ:	  |OP1    |INDX	| RESult ADdRess|
		  |- - - - - - - - - - - - - - -|
 		  | TEXt addr   | accum size    |
		   -----------------------------   
  Inconsistencies in request bits are not likely to be detected.

 %ALLOC first processes the entire list, collecting cumulative information
   about each RESADR requested, summing the size requests (with mods as
   described for MINSZ above).  Then it allocates space for each requested
   area, allowing the user to override each if he REENTERed, and if there
   is TEXt for that area.  It finishes by performing some useful but 
   uninteresting bookkeeping.
⊗

; Get a Stack to hold requests in

HERE (%ALLOC)
	MOVEI	C,MINPDS		;ABOUT 64 WORDS
	PUSHJ	P,CORGET		;THIS USUALLY INITS THE USER TABLE
	 ERR	 <NO CORE FOR ALLOCATION>
	PUSHJ	P,PDPMAK		;A PUSH-DOWN POINTER
	MOVE	P,B			;DITCH THE ALLOC PDL
	MOVEM	B,PDL(USER)		;STORE TEMPORARILY
	PUSH	P,16			;THE RETURN ADDRESS
	ADD	P,X22			;ONE DUMMY ENTRY TO TERMINATE
	SETZM	-1(P)			;0 TERMINATES IT

; Loop to search the space request blocks
; Until further notice:
;  T is →next allocation block.
;  T1 is →next entry specification
;  Q1 is modified T1 -- accounts for STDSPC specifications
;  Q2 is incoming OP-size word
;  A  is →next candidate stack list element
;  Q3 and TEMP used to do RESADR search in already-requested stack list


	MOVE	T,SPLNEK		;LIST OF BLOCKS
	MOVEM	T,%SPL			;LINK BUILT-IN BLOCK EXPLICITLY
	MOVEI	T,%SPL			;ALLOCATE IT FIRST
%AL1:	MOVEI	T1,$SPREQ(T)		;→FIRST REQUEST
%AL2:	SKIPN	Q2,(T1)			;OP WORD
	 JRST	 NXTELT			;NO MORE THIS BLOCK
	MOVE	Q1,T1			;SAVE ADDRESS OF REQUEST
	TLNN	Q2,STDSPC		;A BUILT-IN RESADR/TEXT?
	 AOJA	 T1,DRCT		; NO, GET IT HERE

; T1 incremented because 2-word entry -- Q1 still → 1st word
; Here, there is only a 1-word entry -- the actual RESADR spec
;  found by indexing into table.

	LDB	Q1,[POINT 6,Q2,17]	;THE INDEX
	LSH	Q1,1			;2-WORD ENTRIES ALL
	ADDI	Q1,%STDLST		;HERE'S WHERE THEY LIVE
	HLL	Q2,(Q1)			;USE STANDARD BITS FROM HERE ON
	TLZ	Q2,MINSZ		;NEVER USED FOR MIN WHEN BY INDEX

; Now find the corresponding entry in the accumulated stack entries
;   or add a new entry

DRCT:	HRRZ	Q3,1(Q1)		;ADDRESS OF RESULT
	TLZE	Q2,USRTB		;RESULT IN THE USER TABLE?
	ADD	Q3,GOGTAB		;YES
	MOVEI	A,-1(P)			;FOR SEARCH DOWN STACK
	JRST	%AL4			;GO SEARCH

%AL3:	CAIN	Q3,(TEMP)		;SAME ADDR?
	 JRST	 %AL5			;YES, UPDATE
	SUBI	A,2			;BACK UP ONE
%AL4:	SKIPE	TEMP,(A)		;NEXT SAVED OP WORD
	 JRST	 %AL3			;TRY THIS ONE

; First occurrence of this address, make a place for it

	MOVEI	A,1(P)			;BACK TO THE TOP
	ADD	P,X22			;NEW ENTRY
	SETZM	(A)
	SETZM	1(A)			;VIRGIN ENTRY

COMMENT ⊗
NMIN means MINSZ  on in new spec, OMIN means it's on in stack spec
NSIZ mean that new size≠0, OSIZ etc. -- then
 NMIN∧¬OSIZ		⊃⊃ OSIZ←NSIZ, OMIN←TRUE
 NMIN∧ OSIZ		⊃⊃ no change

¬NMIN∧NSIZ∧OMIN		⊃⊃ OSIZ←NSIZ, OMIN←FALSE
¬NMIN∧¬NSIZ∧OMIN	⊃⊃ no change
¬NMIN∧¬OMIN		⊃⊃ OSIZ←NSIZ+OSIZ, OMIN←FALSE

In the sequel,
 A→current stack entry, T,T1,Q1 unchanged,
 Q2 is NEWSIZ, will be accum SIZ and TEXt addr.
 Q3 is NEWBITS,,RESADR, will be accumulated same.
 TEMP will be old TEX,,SIZ word, LPSA old BITS,,ADR
⊗

%AL5:	HLL	Q3,Q2		;NEW BITS,,RESADR
	HRRES	Q2		;NEW SIZE
	MOVE	TEMP,1(A)	;OLD TEX,,SIZ
	MOVE	LPSA,(A)	;OLD BITS,,ADR
	JUMPL	Q2,AOJBAK	;NO ACTION ON NEGATIVE SIZE
	TLNE	Q3,MINSZ	;BEGIN THE HAIRY CASE STUDY
	 JRST	 INMIN		;MIN ON IN NEW

; ¬NMIN
	TLZN	LPSA,MINSZ	;¬NMIN, OMIN? -- OMIN←FALSE
	 JRST	 ADDIT		;¬NMIN∧¬OMIN, ADD
	JUMPN	Q2,%AL6		;¬NMIN∧ OMIN, NSIZ?
	TLOA	Q3,MINSZ	;¬NMIN∧ OMIN∧¬NSIZ, NMIN←TRUE, NSIZ+OSIZ=OSIZ
%AL6:	HLLZS	TEMP	;¬NMIN∧OMIN∧NSIZ, OSIZ←FALSE,NSIZ+OSIZ=NSIZ,NMIN←FALSE
	JRST	ADDIT		;¬NMIN∧ OMIN, EITHER NSIZ OR OSIZ

; NMIN
INMIN:	TRNE	TEMP,-1		;OSIZ?
	TLZA	Q3,MINSZ	;NMIN∧OSIZ, OSIZ unchg, NMIN←FALSE
	TLZA	LPSA,MINSZ	;NMIN∧¬OSIZ, OSIZ←NSIZ, NMIN←TRUE
	MOVEI	Q2,0		;NMIN∧OSIZ again, OSIZ unchg over add

ADDIT:	OR	Q3,LPSA		;COLLECT BITS
	ADD	Q2,TEMP		;AND SIZE
	TLNN	Q2,-1		;ANY TEXT ADDR?
	HLL	Q2,1(Q1)	;NO, GET FROM OLD IF ANY
	MOVEM	Q3,(A)		;PUT NEW AWAY
	MOVEM	Q2,1(A)
AOJBAK:	AOJA	T1,%AL2		;NEXT ELEMENT THIS BLOCK

NXTELT:	SKIPN	T,(T)		;NEXT BLOCK IN ALLOC LIST?
	 JRST	 NOELT		;NO MORE.
LEP <
	SKIPL	$ITNO(T)	;LEAP REQUESTED?
	JRST	%AL1		;NO.
	MOVE	B,GOGTAB	;WILL PLAY WITH USER TABLE
	SETOM	HASMSK(B)	;SOMEONE WANTS LEAP.
>;LEP
	JRST 	%AL1		;CONTINUE DOWN ALLOC BLOCKS.
NOELT:

; SINCE SYSTEM_PDL ALREADY ALLOCATED AND IN USE, INCREMENT IT IF THE
;  REQUEST EXCEEDS THE DEFAULT
	MOVE	TEMP,PDL(USER)
	PUSH	P,4(TEMP)
	PUSH	P,5(TEMP)	;MAKE SURE P-REQUEST ON TOP
	SETZM	4(TEMP)		;AND THAT IT DOESN'T HAPPEN TWICE

; NOW ALLOCATE THE SPACES, GET OVERRIDES
	SETZM	%ALLCHR		;NO QUESTIONS YET
	SKIPN	%RENSW		;WAS THERE A REENTER?
	 JRST	 NONTR		; NO
	TERPRI
	PRINT	<ALLOC? >
	TTCALL	0,B		;ASK LEADING QUESTION AND GET ANSWER
	TERPRI
	CAIN	B,"Y"		;YES?
	SETOM	%ALLCHR		;YES
	CAIN	B,"N"		;NO, BUT LET ME SEE IT?
	AOS	%ALLCHR		;RIGHT
	SETZM	%OCTRET		;WHEN ON, NO MORE ASKING
NONTR:
ALOC:	SKIPN	T,-1(P)		;WERE THERE ANY ENTRIES?
	 JRST	 DONEE		; MAYBE, BUT NONE LEFT
	MOVS	A,(P)		;SIZE, TEXT
	TRNE	A,-1
	SKIPL	%ALLCHR		;IF TEXT ADDR AND WANTS TO DO IT,
	 JRST	 NOASK		; MUST ASK QUESTIONS

	OUTSTR	(A)		;PRINT IT
	PRINT	<= >
	PUSHJ	P,DECIN
	HRL	A,C		;REPLACE REQUESTED SIZE BY OVERRIDE
NOASK:	HLRZ	C,A		;IN CASE NOBODY ELSE DID
	JUMPE	C,PRIN		;DON'T ALLOCATE 0 AREAS
	HRRZ	TEMP,T		;DEST ADDR
	CAIE	TEMP,PDL(USER)	;THE ONE AND ONLY?
	 JRST	 NOEXP		; NO

;THIS IS THE SYSTEM_PDL REQUEST -- IT MUST OVERLAY THE CURRENTLY
; ALLOCATED STACK
	HRRZ	B,PDL(USER)	;GET PREV INITIAL CORGET ADDRESS
	CAIGE	C,MINPDS	;MUST BE BIGGER
	 MOVEI	 C,MINPDS	; SO MAKE IT BIGGER
	HRL	A,C		;KEEP EVERYBODY UP TO DATE
	ADDI	B,1		;CORGET ADDR
	CAIG	C,MINPDS
	 JRST	 PDPRET		;NO PROBLEM
	SUBI	C,MINPDS	;AMOUNT TO INCREASE BY
;;#  # 4-28-72 DCS UPDATE P'S SIZE FIELD
	HRLZ	TEMP,C		;UPDATE P RIGHT NOW
	SUB	P,TEMP		;SIZE FIELD ONLY
;;#  # 4-28
	PUSHJ	P,CORINC	;INCREMENT TO PROPER SIZE
	 ERR	 <DRYROT -- NO CORE FOR SYSTEM_PDL>
	ADDI	C,MINPDS	;TOTAL SIZE
	JRST	PDPRET
NOEXP:	PUSHJ	P,CORGET	;GET A BLOCK
	 ERR	 <NO CORE AT ALLOCATION>
PDPRET:	TLNN	T,WNTADR	;WANT THE ADDRESS STORED?
	 JRST	 .+3
	MOVEM	B,(T)		;YES, STORE IT
	ADDI	T,1
	TLNN	T,WNTEND
	 JRST	 NOND
	MOVE	D,C		;SIZE
	ADD	D,B		;END ADDR
	MOVEM	D,(T)
	ADDI	T,1
NOND:	PUSHJ	P,PDPMAK
	TLNE	T,WNTPDP
	MOVEM	B,(T)		;WANTS PDP
PRIN:	SKIPN	%ALLCHR		;ARE WE BLABBING?
	 JRST	 SUBJMP		;NOPE
	OUTSTR	(A)
	PRINT	<: >
	HLRZ	C,A		;SIZE AGAIN
	DECPNT	C		;TOTAL ALLOC FOR THIS ONE
	TERPRI
SUBJMP:	SUB	P,X22		;SO MUCH FOR THAT ONE	
	JRST	ALOC		;GET THE NEXT

DONEE:	SKIPN	%ALLCHR		;BLABBING?
	 JRST	 .+3		; NO
	TERPRI↔TERPRI
	SUB	P,X44		;→RETURN ADDRESS (DUMMY AND SYSPDL ENTRIES)

; FINAL BOOKKEEPING

	SETZM	%RENSW		;DON'T ASK EACH TIME
	MOVE	SP,SPDL(USER)	;STRING STACK POINTER
	MOVE	B,ST(USER)	;STRING SPACE BEGINNING
	MOVN	C,-1(B)		;SIZE
	SUBI	C,3		;MINUS OVERHEAD
	MOVEM	C,STMAX(USER)	;SIZE OF STRING SPACE DATA
	HRLI	B,(<POINT 7,0>)
	MOVEM	B,TOPBYTE(USER)	;NEXT FREE BYTE
	IMUL	C,[-5]		;NUMBER OF FREE CHARS
;;#GI# DCS 2-2-72 (1-3) MAKE CAT BETTER -- THIS LEAVES SOME ROOM
	ADDI	C,=15		;LEAVE SOME SLOP FOR INSET, ETC.
;;#GI# (1-3)
	MOVEM	C,REMCHR(USER)
	SKIPE	CONFIG		;COMPILER?
	 SETOM	 SGLIGN(USER)	; YES, STRNGC AND FRIENDS MUST ALIGN STRINGS
	HRROI	TEMP,KTLNK
	POP	TEMP,KNTLNK(USER)
	POP	TEMP,SGROUT(USER)
	POP	TEMP,SETLNK(USER)
	POP	TEMP,SPLNK(USER)
	POP	TEMP,STRLNK(USER);TRANSFER LISTS TO USER TABLE
	PUSHJ	P,STCLER	;CLEAR OUT ALL STRINGS
	MOVEI	TEMP,7		;INITIAL DIGS SETTING
	MOVEM	TEMP,DIGS(USER) ;FOR FLOATING POINT OUTPUT
	MOVEI	TEMP,CHANS(USER);IF CHNL HAS A VALID CHANNEL #,
	HRLI	TEMP,CHNL	; @CDBLOC(USER) REFERS TO ITS
	MOVEM	TEMP,CDBLOC(USER);CDB ADDR IN THE CHANS TABLE
	SETZM	%ERGO		;NO AUTOMATIC CONTINUE FROM ERR.
NOEXPO <
	MOVNI	TEMP,1		;FIND OUT IF ON A DPY
	TTCALL	6,TEMP
	MOVEM	TEMP,DPYSW	;NEG IF DPY
>;NOEXPO
;;#HE# DCS 5-11-72 (2-2) MODIFY VERSION CHECKING, STORAGE METHODS
IFNDEF JOBVER,<EXTERNAL JOBVER>
	MOVEI	LPSA,SPLNEK	;For each element of the space
CHKVRS:	SKIPN	LPSA,(LPSA)	; list, if there is a non-zero 
	POPJ	P,		; version request, use it (lh is
	SKIPN	TEMP,$VRNO(LPSA); SAIL version, rh is user version).
	 JRST	 CHKVRS		;But if there was a previous non-zero
	HLL	TEMP,JOBVER	; request, and if it is not the
	EXCH	TEMP,JOBVER	; same as this one, complain first.
	TRNE	TEMP,-1
	CAMN	TEMP,JOBVER
	 JRST	 CHKVRS
	ERR	<VERSION NUMBER MISMATCH>,1
	 JRST	 CHKVRS
;;#HE# (2-2)


PDPMAK:	MOVNS	C
	SUBI	B,1		;PDP
	HRL	B,C
	POPJ	P,
>;NOLOW
COMMENT ⊗  Utility Subroutines for allocation
⊗
DECIN:
OCTIN:	AOS	(P)
	SKIPE	%OCTRET		;IMMEDIATE RETURN?
	 POPJ	 P,		; YES

	SETZB	C,D
OCTIN1:	TTCALL	0,B
	CAIN	B,177		;RUBOUT?
	 JRST	 RUB		;AYE, THERE'S THE RUB
	CAIN	B,"U"-100	;↑U?
	 JRST	 CTRLU		;INDEED
	CAIN	B,175		;ALTMODE?
	 JRST	 SETRET
	CAIN	B,12		;LINE FEED?
	 JRST	 EPOP		;YES
	CAIL	B,"0"
	CAILE	B,"9"		;I KNOW IT'S CALLED OCTIN,
	 JRST	 OCTIN1		; BUT INPUT IS IN DECIMAL!!
	SETOM	D		;FOUND SOMETHING LIKE A NUMBER
	IMULI	C,=10		;GOOD OLD NUMBER CONVERSION
	ADDI	C,-"0"(B)
	JRST	OCTIN1		;THIS IS A LOOP

SETRET:	SETOM	%OCTRET		;WILL RETURN IMMEDIATELY HENCEFORTH
	TERPRI

EPOP:	SKIPE	D		;FIND ANYTHING?
	SOS	(P)		;YES
CPOPJ:	POPJ	P,

RUB:
CTRLU:	TTCALL	3,[BYTE (7) "↑","U",15,12] ;WON'T THE USER BE
	JRST	OCTIN		;START OVER
SUBTTL	%UUOLNK -- UUO Handler (Dispatch Vector Just Below)

NOLOW <			;INCLUDE IN UPPER SEGMENT.....
↑%UUOLNK:
↑UUOCON:MOVEM	17,%UACS+17		;NOTICE UUO0 IS ABOVE HERE
	MOVEI	17,%UACS
	BLT	17,%UACS+16
	MOVE	P,[XWD -LUPDL,%UPDL]	;SET UP SPECIAL UUO PDL
	MOVE	A,JOBUUO		;GET THE INSTRUCTION
	LDB	B,[POINT 9,A,8]		;GET UUO NUMBER.
	TRNE	B,-1≠17			;CHECK IN RANGE
	JRST	UUOTBL			;ILLUUO
	XCT	UUOTBL(B)		;GO DO RIGHT THING.
	MOVSI	17,%UACS
	BLT	17,17			;RELOAD ACCUMULATORS.
	JRST	2,@UUO0

; UUO TABLE

↑↑UUOTBL:PUSHJ	P,ILLUUO	;0
	PUSHJ	P,PDLOQ 	;1
	PUSHJ	P,FLOAQ 	;2
	PUSHJ	P,FIXQ   	;3
	PUSHJ	P,IOERRR  	;4
	PUSHJ	P,ERRR		;5
	PUSHJ	P,PSIX		;6 -- SIXBIT PRINT.
	PUSHJ	P,ARERRR	;7 -- ARRAY ERROR
	PUSHJ	P,ILLUUO	;10
	PUSHJ	P,DECPNQ	;11
	PUSHJ	P,OCTPNQ	;12
	PUSHJ	P,FLTPNQ	;13
	PUSHJ	P,ILLUUO	;14
	PUSHJ	P,ILLUUO	;15

FLTPNQ:	TERPRI	(<WELL ONE FLOATING PT NUMBER IS 1.0>)
	JRST	GODD
SUBTTL	 ILLUUO, PDLOV, ERR UUO Handlers

DSCR ERROR UUOS
PAR AC FIELD IS INDEX INTO ERROR ROUTINE
SID SAVES THE WORLD
DES THE ASCIZ STRING INDICATED BY THE EFFECTIVE ADDRESS IS TYPED. THEN
 THE ERROR ROUTINE INDICATED BY THE AC FIELD IS EXECUTED.
 IF `GO' IS NOT ON, THE USER IS ALLOWED TO RESPOND WITH ONE OF SEVERAL
 ALTERNATIVES.  ONE ALTERNATIVE IS CONTINUATION IF THE AC FIELD OF THE
 UUO WAS ODD. OTHERWISE, NO CONTINUATION IS POSSIBLE.  THE ACS AT THE
 TIME OF CALL ARE RESTORED IF CONTINUATION OR `DDT' IS CHOSEN.
⊗

ILLUUO:	SKIPA	A,[10B12+[ASCIZ /ILLEGAL UUO  /]]
PDLOQ:	MOVEI	A,[ASCIZ /PDL OVERFLOW/]
ERRR:  ERSEEN←←10000
	SKIPL	CONFIG		;COMPILER ??
	 JRST	 NOCOM
	TLNE	FF,ERSEEN	;IF SYNTAX ERRORS HAVE OCCURED, ONLY
	JRST	[TLNE A,40	;HALT IF THIS IS AN UNRECOV. ERROR.
		 POPJ P,	;JUST CONTINUE....
		TTCALL 3,(A)	;PRINT THE OFFENDING MESSAGE
		 TERPRI <CANNOT CONTINUE ANY FARTHER>
		 SETZM %RECOV	;NOT A CHANCE
		 JRST WATNOW]
NOCOM:
NOEXPO <
	PUSHJ	P,PPRESET	;TURN ON PP 0, RESET POSITION
>;NOEXPO

	TTCALL	3,(A)		;PRINT MESSAGE
	LDB	B,[POINT 4,A,12] ;DISPATCH INDEX
	ROT	B,-1		;LOW ORDER BIT TO SIGN BIT
	MOVEM	B,%RECOV		;MARK %RECOVERABLE (OR NOT)
	PUSHJ	P,@URTBL(B)		;CALL ERROR ROUTINE
	MOVEI	A,0			;INFO FOR MYERR
	SKIPE	ERRSPC			;SPECIAL ERROR ROUTINE??
	PUSHJ	P,@ERRSPC		;YES -- GO DO IT.

LINDUN:	TERPRI
	PRINT	<CALLED FROM >
	HRRZ	A,UUO0
	SUBI	A,1
	PUSHJ	P,OCTPNQ+1
	SKIPGE	CONFIG			;RUNTIMES OR GAG
	 JRST	NOLSCL
	PRINT	 <  LAST SAIL CALL AT >
	MOVE	A,GOGTAB
	HRRZ	A,UUO1(A)
	SOS	A
	PUSHJ	P,OCTPNQ+1

NOLSCL:	TERPRI
	MOVE	A,GOGTAB
	HRRZ	B,TOPBYTE(A)
	CAML	B,STTOP(A);HAVE WE GONE OFF THE DEEP END?
	 JRST	 [PRINT <ALL BETS ARE OFF, FOLKS!
STRING SPACE EXHAUSTED UNEXPECTEDLY. WILL RESTART NOW>
		  JRST  @JOBREN]

	SKIPE	%ERGO
	JRST	GOTRY		;AUTOMATIC CONTINUE SET
WATNOW:	MOVEI	A,"?"		;PRINT ? FOR IRRECOVERABLE ERRORS,
	SKIPGE	%RECOV		; → FOR %RECOVERABLE ONES.
EXPO <
	MOVEI	A,"↑"		;SOMETHING PRINTABLE
>;EXPO
NOEXPO <
	MOVEI	A,"→"		;FOR %RECOVERABLE ONES
>;NOEXPO
	TTCALL	1,A		;PRINT IT
NOEXPO <
	SKIPGE	DPYSW		;ON A DPY?
	DPYOUT	7,DPYMBK	; FLASHING INSTRUCTIONS
>;NOEXPO
	TTCALL	0,B		;GET RESPONSE CHAR
	CAIL	B,"a"		;lower case?
	SUBI	B,40		;YES, CONVERT TO UPPER
NOEXPO <
	SKIPGE	DPYSW
	DPYOUT	7,[0↔0]		;TURN OFF ALL THAT FLASHING
>;NOEXPO
	CAIN	B,"E"		;RE-EDIT?
	 JRST	 EDIT		; YES
	CAIN	B,"T"		;USE TV?
	 JRST	 TVEDIT		; YES
	TTCALL	11,		;CLEAR INPUT BUFFER
	CAIN	B,12		;CONTINUE AUTOMATISCH?
	SETOM	%ERGO		;YES

	CAILE	B,15		;TRY TO CONTINUE?
	JRST	NOCR

	CAIE	B,"α"		;CONTINUE ANYWAY OR
GOTRY:	SKIPGE	%RECOV		;CAN WE CONTINUE?
	POPJ	P,		;YES

	TERPRI	<CAN'T CONTINUE>
	JRST	WATNOW

NOCR:	CAIN	B,"S"
	 JRST	 STRTIT		;RESTART
	CAIN	B,"X"		;EXIT?
	JRST	[
	MOVSI	17,%UACS
	BLT	17,17
	CALL6	EXIT]

NOXIT:	CAIE	B,"D"
	JRST	BADRSP		;DOESN'T KNOW WHAT HE WANTS
GODD:	SKIPN	JOBDDT		;IS DDT IN CORE
	 JRST	 NODDT		;NOPE
	MOVSI	17,%UACS
	BLT	17,17
	JRST	@JOBDDT

NODDT:	TERPRI	<NO DDT>
	JRST	WATNOW

BADRSP:	SKIPE	A,ERRSPC	;IS THERE A COMPILER ROUTINE?
	SKIPN	A,-1(A)		;YES, IS THERE AN FTDEBUGGER?
	 JRST	 RELYBD		;NO OR NO
	CAIE	B,"L"		;WANT TO LOOK AT STACK?
	 JRST	 RELYBD		;NO, ALL THAT WORK FOR LITTLE
	TERPRI	<YOU ARE IN THE COMPILER DEBUGGER>
	PUSHJ	P,(A)		;GO DEBUG
	JRST	WATNOW

RELYBD:	PRINT	<REPLY [CR] TO CONTINUE,
[LF] TO CONTINUE AUTOMATICALLY,
"D" FOR DDT, "E" TO EDIT,
"X" TO EXIT, "S" TO RESTART>
	JUMPE	A,CRL
	PRINT	<,
"L" TO LOOK AT THE STACK>
CRL:	TERPRI
	JRST	WATNOW


IOERRR:	TERPRI	
	TTCALL	3,(A)
	TLNE	A,740		;ANY AC AT ALL?
	 PUSHJ	 P,SIXPRT	;YES, ASSUME 14-15, SIXBIT IN LPSA
	TERPRI
	CALLI			;AVOID CLOSING FILES
	CALL	[SIXBIT/EXIT/]	;FAIL WON'T LET ME USE CALL6
STRTIT:	HRRZ	A,JOBSA
	JRST	(A)


DSCR ARRAY ERROR UUO
PAR ARRAY NAME STRING DESCRIPTOR ADDRESS IS EFFECTIVE ADDR
 INDEX NUMBER IS AC FIELD.
DES ARRAY NAME, INDEX NUMBER ARE PRINTED. THEN ERROR UUO CODE
 IS ENTERED AS ABOVE.
⊗

ARERRR:
NOEXPO <
	PUSH	P,PPRETR	;IN LINE CALL
PPRESET:
	SKIPL	DPYSW		;ON A DPY?
	POPJ	P,		;NO, DON'T BOTHER
	OPDEF	PPIOT [702B8]
	PPIOT	1,400000
	DPYPOS	(-200)		;RESET X POS
	DPYSIZ	(3,5)		;RESET GLITCHES
PPRETR:	POPJ	P,.+1
>;NOEXPO
	PRINT	<INVALID INDEX NO. >
	LDB	A,[POINT 4,JOBUUO,12]
	PUSHJ	P,DECPNQ+1
	PRINT	< FOR ARRAY >
	SETZM	%RECOV		;NON-RECOVERABLE ERROR!
	PUSHJ	P,PRASC
	JRST	LINDUN
SUBTTL	  Special Printing Routines For Error Handler

DSCR UUO ERROR MESSAGE ROUTINES AND THEIR INDICES (AC FIELD OF UUO)
⊗

↑↑URTBL:UPOPJ			; 0- 1 -- NO ACTION
	.PRSM			; 2- 3 -- PRINT SYMBOL PTD TO BY LPSA (SAIL)
	PRASC			; 4- 5 -- PRINT SYMBOL PTD TO BY UUO INSTR
	ACPRT			; 6- 7 -- PRNT VAL OF AC IN INSTR PRECDNG UUO
	UUOPRT			;10-11 -- PRINT THE UUO
	AC1PRT			;12-13 -- PRINT AC FIELD ASSUMING RETURN FROM
				; 	  CALL IS IN UUO1(GOGTAB)
	SIXPRT			;14-15 --PRINT LPSA AS SIXBIT

UUOPRT: HLRZ	A,40		;LH
	PUSHJ	P,OCTPNQ+1	;TYPE IT
	HRRZ	A,40		;RH
	JRST	OCTPNQ+1	;IT TOO

DSCR PRSYM -- PRINT SYMBOL NAME
PAR SAIL SEMANTICS BLOCK ADDRESS IN LPSA
RES TYPES $PNAME STRING FROM BLOCK
SID DESTROYS A,B
⊗


	$PNAME ←← 1

PRASC:	SKIPA	A,JOBUUO	;→STRING DESCRITPOR
.PRSM:	HRRI	A,$PNAME(LPSA)	;→STRING DESCRIPTOR
	HRRZ	B,(A)		;#CHARACTERS
	MOVE	A,1(A)		;STRING BP
	MOVEI	D,0		;NO ADJUSTMENT
	JRST	PRSL1		;WON'T WORK FOR ZERO LENGTH STRINS

PRSL:	ILDB	C,A		;CHARACTER
	ADDI	C,(D)		;ADJUSTMENT
	TTCALL	1,C		;TYPE IT
PRSL1:	SOJGE	B,PRSL
UPOPJ:	POPJ	P,


AC1PRT:	MOVE	A,GOGTAB	;GET USER TABLE PTR
	SKIPA	A,UUO1(A)	;SOMEONE STORED RIGHT THING HERE

ACPRT:	HRRZ	A,UUO0
	LDB	A,[POINT 4,-2(A),12] ;AC # FROM PREV INSTR
	ADDI	A,%UACS
	JRST	DECPNQ		;PRINT IT IN DECIMAL

SIXPRT:	SKIPA	A,[POINT 6,LPSA];GET FROM HERE
PSIX:	HRLI	A,(<POINT 6,0>) ;UUO ADDR IS ADDR OF SIXBIT
	MOVEI	D,40		;ADJUSTMENT
	MOVEI	B,6		;PRINT 6 CHARS
	JRST	PRSL1

SUBTTL	  Code to Handle Linkage to Editors

TVEDIT:	TDZA	13,13		;FLAG AS TV
EDIT:	MOVNI	13,1
	PUSH	P,13
	SETZB	13,14		;PREPARE FOR PROVIDING
	SETZB	15,16		;STOPGAP WITH FILE NAME,
	SETZB	11,12		; PAGE AND LINE NUMBERS, SEQUENTIAL LINE #
	TTCALL	0,B		;SEE IF FILE NAME SPECIFIED
	CAIE	B,15		;CR?
	 JRST	 GTNAM		; NO, NAME SPECIFIED

AUTO:	TTCALL	0,B		;SNARF UP LINE FEED AFTER CR
	MOVEI	A,1
	SKIPE	ERRSPC
	 PUSHJ	 P,@ERRSPC	;SPECIAL FOR COMPILER....
	JRST	GTIT		;GET QQSVED.RPG

GTNAM:	CAIE	B," "		;DELETE LEADING BLANKS
	 JRST	 MKNAMM
	TTCALL	0,B
	JRST	GTNAM

MKNAMM:	CAIN	B,15		;GO BACK ON CR
	 JRST	 AUTO
	MOVE	C,[POINT 6,13] ;COLLECT FILE NAME HERE
MKNLP:	CAIE	B," "		;DONE?
	CAIN	B,15
	 JRST	 GTIT1		; YES
	SUBI	B,40
	CAIN	B,"."-40
	SKIPA	C,[POINT 6,14] ;ADJUST TO GET EXTENSION
	IDPB	B,C		;CHAR OF FILENAME
	TTCALL	0,B
	JRST	MKNLP


GTIT1:	CAIN	B,15
	TTCALL	0,B

GTIT:	POP	P,A		;TV/SOS FLAG
	EXCH	13,14		;EXT IN REG PRECEDING NAME?
;HERE TO RUN ANY PROGRAM, EITHER SOS OR COMPIL.
; REGISTERS HAVE GOODIES IN THEM:
;		13	FILE EXTENSION IN SIXBIT
;		14	FILE NAME IN SIXBIT
;		15	LINE NUMBER IN ASCII.
;		16	PAGE NUMBER (BINARY)
;IF AC 14 IS ZERO, THIS MEANS NO FILE HAS BEEN
; SPECIFIED, AND WE WILL USE "COMPIL" TO REPEAT THE
; LAST EDIT COMMAND (THIS IS NOT A FEATURE ON MOST
; STANDARD DEC SYSTEMS -- SEE R SPROULL)
NOEXPO <
	MOVEI	P,2
	LOAD6	(2,<SYS>)	;ASSUME GET TO EDITOR VIA RPG
	LOAD6	(4,<DMP>)
	MOVEI	6,0
	MOVEI	5,777777	;TELLS RPG: "EDIT"
	LOAD6	(3,<RPG>)
	JUMPE	14,SWAPIT
	MOVEI	5,1		;START AT RPG LOC IN EDITOR
	LOAD6	(3,<SOS>)	;NOW ASSUME SOS
	JUMPL	A,SWAPIT	;YES
	LOAD6	(3,<TV>)	;NO, TV
	MOVE	15,12		;GET SEQUENTIAL LINE NUMBER
SWAPIT:	CALL6	(P,SWAP)	;SEE YOU AROUND
>;NOEXPO
; ELSE FALL INTO EXPO VERSION ....

COMMENT ⊗ EXPORT VERSION OF EDITOR-INTERFACE
 PROVIDED BY R. SPROULL, 11-18-70
  SEE HIM FOR DETAILS ON DIDDLES TO CCL AND EDIT10
⊗
EXPO <
	JUMPN	14,EDITG	;IF FILE, FIRE UP SOS
	MOVE	P,[XWD -1,[SIXBIT /SYS/
			   SIXBIT /COMPIL/
			  0 ↔ 0 ↔ 0 ↔ 0 ]]
	CALL6	(P,RUN)		;GO RUN IT.
	JRST	4,0
EDITG:	PUSHJ	P,RPGDSK ;SET UP FOR FILE
	MOVE	2,14 	;GET THE FILE
	PUSHJ	P,SXCON
	MOVEI	1,"."
	SKIPN	2,13     ;EXTENSION
	JRST	NOEXT
	PUSHJ	P,OUT1
	HLLZS	2	;EXTENSION.
	PUSHJ	P,SXCON
NOEXT:	SKIPN	11		;PROJ,PROG #
	JRST	NOPPN
	MOVEI	1,"["
	PUSHJ	P,OUT1
	HLRZ	1,11
	PUSHJ	P,OCTO	;OUTPUT OCTAL
	MOVEI	1,","
	PUSHJ	P,OUT1
	HRRZ	1,11
	PUSHJ	P,OCTO
	MOVEI	1,"]"
	PUSHJ	P,OUT1
NOPPN:	PUSHJ	P,CRLF
	JUMPE	15,GOED10	;IF NO LINE NUMBER, DO NOT DO THIS.
	MOVEI	1,"P"
	PUSHJ	P,OUT1
	MOVE	2,15		;LINE NUMBER
	TRZ	2,1	;FOR SURE?
ASCO:	MOVEI	1,0
	LSHC	1,7
	PUSHJ	P,OUT1
	JUMPN	2,ASCO
	MOVEI	1,"/"
	PUSHJ	P,OUT1
	MOVE	1,16	;PAGE NUMBER
	PUSHJ	P,OUTDEC
	PUSHJ	P,CRLF
GOED10:	MOVE	1,PPMAX+2 ;SIZE
	ADDI	1,4
	IDIVI	1,5	  ;TO WORDS
	MOVNS	1
	HRLS	1
	HRR	1,PPMAX	  ;BUFFER START
	ADDI	1,1
	MOVEM	1,PPMAX+2
	MOVSI	1,'EDT'
	EXCH	1,PPMAX+1
	MOVE	2,[XWD 3,PPMAX+1]
	CALLI	2,44	;WRITE IT
	JRST	DSKIT
EDT10R:	MOVE	P,[XWD 1,[SIXBIT /SYS/
			  SIXBIT /SOS/
			  0↔0↔0↔0]]
	CALL6	(P,RUN)
	JRST	4,.
DSKIT:	SETSTS	1,16	;DO NOT LOSE BUFFERS
	MOVEM	1,PPMAX+1
	CALLI	2,30	;JOB NUMBER
	MOVSI	1,'EDT'	;TO FILE NAME
	MOVEI	4,3
DGLP:	IDIVI	2,=10
	IORI	1,20(3)
	ROT	1,-6	
	SOJG	4,DGLP
	MOVSI	2,'TMP'
	SETZB	3,4
	ENTER	1,1
	CALLI	12		;FATAL
	SETSTS	1,0
	CLOSE	1,0		;FINISH
	JRST	EDT10R
RPGDSK:	CALLI
	INIT	1,0
	SIXBIT	/DSK/
	XWD	PPMAX,0
	CALLI	12
	OUTBUF	1,0
	OUTPUT	1,0
	SETZM	PPMAX+2
	MOVEI	1," "
OUT1:	AOS	PPMAX+2
	IDPB	1,PPMAX+1
	POPJ	P,
SXCON:	MOVEI	1,0
	LSHC	1,6
	ADDI	1,40
	PUSHJ	P,OUT1
	JUMPN	2,SXCON
	POPJ	P,
OCTO:	IDIVI	1,10
	HRLM	2,(P)
	SKIPE	1
	PUSHJ	P,OCTO
	HLRZ	1,(P)
	ADDI	1,"0"
	JRST	OUT1
OUTDEC:	IDIVI	1,=10
	HRLM	2,(P)
	SKIPE	1
	PUSHJ	P,OUTDEC
	HLRZ	1,(P)
	ADDI	1,"0"
	JRST	OUT1
CRLF:	MOVEI	1,15
	PUSHJ	P,OUT1
	MOVEI	1,12
	JRST	OUT1
>;EXPO
SUBTTL	 DECPNT, OCTPNT, FIX, FLOAT UUOs

DSCR OCTPNT, DECPNT UUO'S
PAR ADDR OF WORD TO BE PROCESSED IS EFFECTIVE ADDR
RES DECPNT -- WORD TYPED IN DECIMAL
 OCTPNT -- OCTAL
⊗



OCTPNQ: HRRZ	A,(A)
	MOVEI	C,10	;KEEP RADIX IN C.
	JRST	PNT

DECPNQ:	MOVE	A,(A)
	MOVEI	C,=10
	JUMPGE	A,PNT	; GREATER 0.
	PRINT	<->
	MOVMS	A		; FOO1 ← ABS(FOO1);
PNT:	IDIV	A,C	;FAMOUS DEC RECURSIVE NUMBER PRINTER.
	IORI	B,"0"
	HRLM	B,(P)
	SKIPE	A
	PUSHJ	P,PNT
	HLRZ	B,(P)
	TTCALL	1,B
	POPJ	P,

DSCR FIX UUO (FIXQ)
PAR EFFECTIVE ADDR → WORD TO BE CONVERTED
RES FIXED POINT EQUIVALENT IN AC SPECIFIED IN AC FIELD OF UUO
⊗
FIXQ:	TRNN	A,777760	;IN AC?
	ADDI	A,%UACS		;YES
	MOVE	B,(A)		;GET ARGUMENT
	MULI	B,400	;THIS ALGORITHM STOLEN FROM F4.
	TSC	B,B
	EXCH	B,C
	ASH	B,-243(C)
	JRST	FXFLT		;STORE IN RIGHT PLACE.
	POPJ	P,

DSCR FLOAT UUO (FLOAQ)
RES LIKE FIX, BUT RETURNS FLOATING POINT EQUIVALENT OF ITS ARGUMENT
⊗
FLOAQ:	TRNN	A,777760	;IN AC?
	ADDI	A,%UACS		;YES
	MOVE	B,(A)		;GET ARGUMENT
	IDIVI	B,1B18
	SKIPE	B
	TLC	B,254000
	TLC	C,233000
	FAD	B,C
FXFLT:
	LDB	A,[POINT 4,A,12] ;RESULT REGISTER
	MOVEM	B,%UACS(A)	;STORE RESULT
	POPJ	P,
SUBTTL	 DSPLIN, etc.for Disp. Text Line on Error (Compiler)

DSCR DPYCLR
CAL PUSHJ
RES RESETS III DPY STATE IF A III DPY IS AROUND
⊗

NOEXPO <
↑DSPCLR:
	SKIPGE	DPYSW
	DPYCLR
	POPJ	P,

>;NOEXPO


NOEXPO <
↑↑DPYMBK:	DPYMSG
	DPYSVV-DPYMSG+1		;DPYOUT HEADER BLOCK

DPYMSG:	0
	AIVECT	(=100,=400)	;MOVE TO RIGHTOF RAID SCREEN
	ASCID	/REPLY [CR] TO CONTINUE,
/
	RIVECT	(=612,0)	;GET OUT THERE AGAIN
	ASCID 	([LF] TO CONTINUE AUTOMATICALLY,
(
	RIVECT	(=612,0)
	ASCID	("D" FOR DDT, "E" TO EDIT, "T" TO TVEDIT,
(
	RIVECT	(=612,0)
	ASCID	("X" TO EXIT, "S" TO RESTART,
(
DPYSVV:	DPYJMP	DPYMSG

>;NOEXPO
SUBTTL	SAVE, RESTR, INSET -- General Utility Routines

DSCR SAVE
CAL PUSHJ
DES This routine saves registers 0-CHNL (12) in the user
 RACS area. It also saves the return
 address (-1(P)) in UUO1(USER), for traditional reasons,
 for the error message printout routines.
 Register USER is loaded but not saved, as is register
 TEMP
⊗
↑SAVE:	MOVE	USER,GOGTAB	;→USER RE-ENTRANT TABLE
	HRRZI	TEMP,RACS(USER)	;XWD FF,SAVEADDR
	BLT	TEMP,RACS+CHNL(USER) ;SAVE FF THRU CHNL
	MOVE	TEMP,-1(P)	;RETURN ADDR FROM I/O CALL
	MOVEM	TEMP,UUO1(USER)	;STORE RETURN
	POPJ	P,

DSCR RESTR
PAR LPSA -- XWD FOR ADJUSTING P-STACK (#PARAMS+RETURN ADDR)
CAL JRST
RES ACS are restored from RACS, stack is adjusted using LPSA,
 return is made through UUO1(USER)
⊗

↑RESTR:	MOVSI	TEMP,RACS(USER)	;XWD SAVEADDR,FF
	BLT	TEMP,CHNL	;RESTORE
	SUB	P,LPSA		;ADJUST STACK
	JRST	@UUO1(USER)	;RETURN

DSCR STACSV
CAL PUSHJ
DES SAVES ACS 0-15 IN AREA STACS
SID NONE
⊗

↑STACSV:	PUSH	P,15
	MOVE	15,GOGTAB
	MOVEM	14,STACS+14(15)
	POP	P,STACS+15(15)
	HRRZI	14,STACS(15)
	BLT	14,STACS+13(15)
	MOVE	14,STACS+14(15)
	MOVE	15,STACS+15(15)
	POPJ	P,

DSCR STACRS
CAL PUSHJ
DES RESTORES ACS 0-15 FROM AREA STACS
⊗

↑STACRS:	MOVE	15,GOGTAB
	HRLZI	15,STACS(15)
	BLT	15,15
	POPJ	P,



DSCR INSET
CAL PUSHJ
RES String Space is adjusted so that next created string will start
 on a full-word boundary.
SID USER→GOGTAB
DES REMCHR is first adjusted, and STRNGC called if necessary.
 Then TOPBYTE is adjusted.
⊗


↑INSET:	MOVE	USER,GOGTAB	;MAKE SURE
;;#GI# DCS 2-5-72 REMOVE TOPSTR
	HLL	TEMP,TOPBYTE(USER)
	HRRI	TEMP,[BYTE (7) 0,4,3,2,1,0]
	ILDB	TEMP,TEMP	;ADJUSTMENT NEEDED.
	ADDM	TEMP,REMCHR(USER)	;UPDATE REMCHR.
	SKIPL	TEMP,TOPBYTE(USER)
	ADDI	TEMP,1
	HRLI	TEMP,440700	;POINT 7, WORD
	MOVEM	TEMP,TOPBYTE(USER)	;AND SAVE
	POPJ	P,
>;NOLOW
ENDCOM(LUP)
COMPIL(COR,<CORREL,CORGET,CORINC,CANINC,CORBIG>
	   ,<GOGTAB>
	   ,<CORGET, CORREL, ... -- CORE ALLOCATION ROUTINES>)
SUBTTL	Core Service Routines -- General Description

DSCR BEGIN CORSER
⊗
IFN ALWAYS,<BEGIN CORSER>
Comment ⊗ These are the core allocation routines for both the compiler
	and the code it compiles.  Core comes in "BLOCKs."  A block may be any
	(reasonable) length, and has the following format:

HEAD:	→PREV,,→NEXT		;if block not in use, free storage list pointers
		SIZE		;GREATER 0 if free, LESS0 if in use
	<SIZE-3 data words>	;whatever is to go here
	x00000,,→HEAD		;x=1 if in use, 0 if free

→PREV is zero if this block is first on free storage list. →NEXT is zero if last

In the beginning, the world starts out as one big block, occupying space from
	the end of the (GOGTAB→) user table to @JOBREL. Once a MOVE USER,GOGTAB
	has been done, LOWC(USER) and TOP(USER) indicate the total size of
	available core. FRELST(USER) → the first (only) block in free storage.
 
If GOGTAB is 0, CORGET will create a user table and make the remaining space
	look like a BLOCK.  It will create a user table and point GOGTAB at it.
	It also assures that DDT symbols are below JOBSA(lh).  Then it sets
	JOBFF to =76K out of pure spite.  Now CORGET operations may be issued.

CORGET is called with the desired size in SIZ (C). The free storage list is
	searched for the first free block (BLK) satisfying the request. The
	required block is taken from lower addresses of BLK and BLK is adjusted.
	If requested size is within a few words of the free size, all of BLK is
	given to the user. The resultant address is returned in THIS (B).

If there is no block on FRELST(USER) big enough, or if ATTOP(USER) ≠ 0, CORGET
	checks XPAND(USER) for permission (0) to expand core.  If granted, a new
	block is formed at the top after obtaining more core. It is merged with
	the top block if it is free, then the requested block is allocated from
	it.  CORGET is simple.

CORGET skips if it is successful. It does not skip if it needs to expand and
	either XPAND(USER) ≠ 0 or the CORE UUO fails.

The secret is CORREL. No compacting is done, but CORREL will merge a returning
	block with any neighboring free block.  It can do this because it can
	tell the status of each neighbor by looking at the size (POS if free)
	field or x-bit (off if free).  This tends to reduce checkerboarding.

CORREL is called with a pointer to the block to be released in THIS (B).
	It returns nothing, nor does it ever skip.

CORBIG returns in SIZ the size of the largest available block. ⊗
NOLOW <			;INCLUDE IN UPPER SEGMENT.
SUBTTL	 Special AC Declarations

DEBCOR ←←0		;SWITCH FOR CORE DEBUGGING ROUTINES.
;  ACS  

SIZ	←←  3			;SIZE OF BLOCK BEING OBTAINED OR RELEASED
THIS	←←  2			;POINTER TO SAME
NEXT	←←  1			;POINTER TO SUCCESSOR
PREV	←←  5			;POINTER TO PREDECESSOR
LAST	←←  6			;POINTER TO NEXT-HIGHER NEIGHBOR

TRIVIAL ←←=10			;AMOUNT WE'RE WILLING TO WASTE
SUBTTL	  Utility Routines

DSCR UNLINK
CAL PUSHJ
PAR →Core block to be removed in AC THIS (2)
RES block is removed from CORSER free storage list
SID ACs NEXT (1) and PREV (5) are given appropriate values
⊗

UNLINK:	
	HRRZ	NEXT,(THIS)		;→NEXT BLOCK
	HLRZ	PREV,(THIS)		;→PREVIOUS BLOCK
	SKIPN	PREV			;IF A PREV BLOCK DOES NOT EXIST,
	 MOVEI	 PREV,FRELST(USER)	; USE FRELST POINTER
	HRRM	NEXT,(PREV)		;CHANGE ITS NEXT FIELD
	SKIPE	NEXT			;IF A NEXT BLOCK EXISTS,
	 HRLM	 PREV,(NEXT)		; CHANGE ITS PREV FIELD
	POPJ	P,			;BLOCK IN "THIS" IS NO LONGER ON FRELST

DSCR RELINK
CAL PUSHJ
PAR AC THIS → core block to be placed on free storage list
 AC LAST → last word of block +1
 AC SIZ has size of this block
DES block is placed on CORSERs free storage list
SID AC NEXT (1) is given the appropriate value
⊗

RELINK:
	HRRZM	THIS,-1(LAST)		;X-BIT ← 0, RH ← PTR TO HEAD
	MOVEM	SIZ,1(THIS)		;GREATER 0 SIZE FIELD ⊃ FREE BLOCK
	SKIPE	NEXT,FRELST(USER)	;PLACE NEW BLOCK ON FRONT OF FRELST
	 HRLM	 THIS,(NEXT)		; IF THERE IS ONE
	HRRZM	NEXT,(THIS)		;POINT TO NEXT FROM THIS
	HRRZM	THIS,FRELST(USER)	;UPDATE FRELST POINTER
	POPJ	P,			;RETURN

DSCR CORE2I
CAL PUSHJ
DES Initializes second segment core if there is a global model
⊗

GLOB <
IFN 0,<
↑GLCOR:	
	SKIPE	GLBPNT
	POPJ	P,		;ALREADY INITIALIZED.
	MOVEM	16,GLUSER+LEABOT+16
	MOVEI	16,GLUSER+LEABOT
	BLT	16,GLUSER+LEABOT+15
				;SHALL NOT CLOBBER ACCUMULATOR 1.
	MOVEI	3,3(13)  	;GET SIZE REQUIRED.PLUS SOME BECAUSE BLT LOSES.
	PUSHJ	P,CORE2		;GET SECOND SEGMENT CORE.
	JRST	[TERPRI <NO CORE FOR GLOBAL MODEL>
		 CALLI	12]
	SUBI	2,1
	MOVEM	2,GLBPNT	;AND RECORD IT.
	SETZM	1(2)		;FIRST WORD.
	HRRI	2,2(2)		;SECOND WORD.
	HRLI	2,-1(2)		;FIRST WORD.
	ADDI	3,-2(2)		;LENGTH.
	BLT	2,(3)		;ZERO IT.....
	MOVSI	16,GLUSER+LEABOT
	BLT	16,16		;RESTORE ALL LOADER'S AC'S AGAIN.
	POPJ	P, 		;AND GO AWAY.
>
↑CORE2I: 
	PUSH	P,USER
	MOVE	USER,[XWD GLUSER+LEABOT+20,GLUSER+LEABOT+21]
	SETZM	GLUSER+LEABOT+20
	BLT	USER,GLUSER+ZAPEND
	POP	P,USER		;NOW DATA AREA IS ZERO.
	MOVEI	USER,GLUSER	;SET UP FOR CORE2.
	PUSHJ	P,JUSTSAVE	;AND SAVE AC'S
	SETOM	CORLOK			;THE LOCK ...
	SETOM	GLBPNT			;AND THE SWITCH SAYING INITED.
	MOVE	THIS,TOP2		;LAST ADDRESS IN SEC. SEG USED.
	ADDI	THIS,1
	MOVEM	THIS,LOWC(USER)		;SAVE FOR LATER
	PUSHJ	P,NEWB2			;AND LINK UP.
	JRST	BUFRST			;ALL DONE INITIALIZING.

DSCR 2d SEGMENT CORE CONTROL STORAGE
⊗

CORLOK:	0

CR2BEG:	BLOCK ZAPEND-ZAPBEG+1		;AREA FOR ALL OTHERS.

↑↑GLUSER←CR2BEG-ZAPBEG			;AND THE MAGIC INDEX.
	INTERNAL GLUSER

>;GLOB


DSCR BUFRST
CAL PUSHJ or JRST
RES restores ACs from CORSER routines, and returns
⊗

BUFRST:	
IFN DEBCOR,<
	SKIPE	PRTCOR			;SHOULD WE DEBUG?
	JFCL
>
	MOVSI	TEMP,BUFACS(USER)
	BLT	TEMP,LAST
	POPJ	P,

DSCR BUFSAV
CAL PUSHJ
RES Saves ACs for CORSER routine
 Initializes CORSER storage, obtains USER TABLE if GOGTAB is 0
⊗

BUFSAV:	
GLOB <
	SKIPN	GLBPNT		;HAS GLOBAL MODEL BEEN INITIALIZED?
	 PUSHJ	P,CORE2I		;NO --INITIALIZE IT.
>;GLOB
	SKIPE	USER,GOGTAB		;CAN WE GO AHEAD?
	 JRST	 JUSTSAVE		; YES

Comment ⊗ Use SALTAB and forget the rest if SALTAB is there. Otherwise
	set up a user table.  Don't use THIS or SIZ (B or C). ⊗

NOEXPO <
	MOVEI	TEMP,=76*=1024		;ONE REALLY MUST KNOW WHAT HE
>;NOEXPO
EXPO <
	MOVEI	TEMP,-1			;FOR MAX CORE 
>;EXPO
	MOVEM	TEMP,JOBFF		; IS DOING
 
;	SKIPE	USER,SALTAB		;OTHERS CAN SPECIFY SAIL SPACE
;	MOVEM	USER,GOGTAB		;SET UP GOGTAB IF SALTAB NON-ZERO
;	JUMPN	USER,JUSTSAVE		;DON'T GO THRU SAIL's ALLOCATION

; ASSUME THAT THE WORLD IS NEW

	HLRZ	USER,JOBSA		;USER TABLE ADDRESS
	MOVEM	USER,GOGTAB		;THIS TIME FOR SURE
	SKIPN	JOBDDT			;IF DDT IS IN CORE,
	 JRST	 NODDT			; MAKE SURE ITS SYMBOLS ARE PROTECTED
	HRRZ	TEMP,JOBSYM		;IF JOBSYM IS BELOW JOBFF, THEN 
	CAML	TEMP,USER		; ASSUME ALL SYMBOLS ARE BELOW.
	 TERPRI	 <YOUR SYMBOLS ARE SOON TO BE OBLITERATED>


NODDT:	MOVEI	TEMP,ENDREN-CLER+=2000(USER)	;MAKE SURE
	CAMGE	TEMP,JOBREL		; ENOUGH CORE EXISTS
	 JRST	 CORTHER		; FOR USER TABLE

	CALL6	(TEMP,CORE)		;GET ENOUGH
	 ERR	 <DRYROT -- NO ROOM FOR USER TABLE>

CORTHER:
	SETZM	(USER)			;CLEAR USER TABLE
	HRL	TEMP,USER
	HRRI	TEMP,1(USER)
	BLT	TEMP,ENDREN-CLER(USER)
	MOVEI	THIS,ENDREN-CLER(USER)	;SET UP LIMITS OF FREE SPACE
	MOVEM	THIS,LOWC(USER)		; BOTTOM
	PUSHJ	P,NEWBLK		;MAKE NEW AREA INTO A FREE BLOCK
	JRST	JUSTSAVE		;SAVE ACS

GLOB <
NEWB2:	CALLI	LAST,SEGSIZUUO		;FIND OUT HOW BIG.
	TRO	LAST,400000		;SINCE ANDY DOES NOT GIVE ME THIS.
	JRST	NEWB1
>;GLOB
NEWBLK:	
	HRRZ	LAST,JOBREL		;END OF BIG BLOCK
NEWB1:	SETZM	(THIS)			;POINTERS WORD IN BIG BLOCK
	ADDI	LAST,1			;CONFORM TO "LAST" STANDARDS
	MOVEM	LAST,TOP(USER)		;TOP OF FREE SPACE
	PUSH	P,SIZ			;SAVE SIZE
	MOVE	SIZ,LAST		;COMPUTE SIZE OF NEW BLOCK
	SUB	SIZ,THIS		;SIZE OF BIG BLOCK
	PUSHJ	P,RELINK		;PUT ON FREE STORAGE LIST
	POP	P,SIZ			;GET SIZ BACK
	POPJ	P,


JUSTSAVE:
	MOVEI	TEMP,BUFACS(USER)
	BLT	TEMP,BUFACS+LAST(USER)
IFN DEBCOR,<
	SKIPE	PRTCOR			;SHOULD WE DEBUG?
	PUSHJ	P,CORPRT		; YES
>
	POPJ	P,


IFN DEBCOR,<
↑PRTCOR:	0
>
SUBTTL	 CORGET

DSCR CORGET
CAL PUSHJ
PAR size of desired block in AC  C (3)
RES 	SUCCESS: addr of block in B, skip-return
	FAILURE: no-skip
SID none, except when called with GOGTAB 0 -- should only be done by experts
DES a block of at least the required size is obtained using first-fit algorithm.
	Up to 10 extra words may be returned, but this is not reflected in C.
⊗

↑CORGET:
IFN DEBCOR,<
	SKIPE	PRTCOR
	 TERPRI	 <CORGET: >		;TELL THE PEOPLE WHO YOU ARE
>
	PUSHJ	P,BUFSAV		;SAVE AC'S, INITIALIZE WORLD PERHAPS
GLOB <
	SKIPN	USCOR2(USER)		;ARE WE INSTRUCTED TO USE CORE2?
	JRST	COR21			;NOPE -- GO AHEAD.
↑↑CORE2: SKIPN	GLBPNT			;HAS IT BEEN INITIALIZED?
	 PUSHJ	P,CORE2I		;NO -- BUT NOW.
	AOSE	CORLOK			;CAN WE GET THROUGH THE LOCK?
	JRST	[SOS CORLOK		;APPARENTLY NOT.
		 PUSHJ	P,WAITQQ	;WAIT
		 JRST .-1]
	MOVEI	USER,GLUSER		;USE THIS VERSION OF USER.
	PUSHJ	P,JUSTSAVE		;JUST SAVE THE ACCUMULATORS.
>;GLOB


COR21:	ADDI	SIZ,3			;3 WORDS FOR CONTROL INFO
	SKIPE	ATTOP(USER)		;IF USER REQUESTS IT, GET BLOCK
	 JRST	 EXPAND			; AT TOP OF CORE

	MOVEI	THIS,FRELST(USER)	;THIS WILL POINT TO THE FIRST GOOD BLOCK

GETLUP:	HRRZ	THIS,(THIS)		;→NEXT FREE BLOCK
	JUMPE	THIS,EXPAND		;TRY TO EXPAND CORE, NONE EXIST YET
	CAMLE	SIZ,1(THIS)		;WILL IT FIT?
	 JRST	 GETLUP			; NO, TRY NEXT

GETCOR:	AOS	(P)			;SUCCESS GUARANTEED
	HRRZM	THIS,BUFACS+THIS(USER)	;RESULT(ALMOST)
	PUSHJ	P,UNLINK		;UNLINK THIS BLOCK
	MOVE	LAST,1(THIS)		;REAL BLOCK SIZE
	CAIGE	LAST,TRIVIAL(SIZ)	;IS DIFFERENCE NEGLIGIBLE?
	 JRST	 [MOVSI TEMP,400000	;YES, USE WHOLE THING --
		  ADD   LAST,THIS	; MARK X-BIT TO INDICATE IN USE
		  HLLM	TEMP,-1(LAST)
		  JRST	GETOUT]		;AND GO FINISH OUT

	MOVEM	SIZ,1(THIS)		;NEW SIZE FOR RESULT
	HRRZ	TEMP,THIS		;SAVE START OF BLOCK (RESULT)
	ADD	THIS,SIZ		;NEW START FOR REMAINING FREE STUFF
	SUB	LAST,SIZ		;NEW SIZE FOR REMAINS
	MOVE	SIZ,LAST
	ADD	LAST,THIS		;NEW END FOR REMAINS
	HRLI	TEMP,400000		;TURN X-BIT ON
	MOVEM	TEMP,-1(THIS)		;IN USER'S BRAND NEW BLOCK
	PUSHJ	P,RELINK		;RELINK REMAINS, RESTORE ACS


GETOUT:	PUSHJ	P,GETRST		;RESTORE ACS
	SETZM	(THIS)			;PTR RETRIEVED FROM STORAGE
	MOVNS	1(THIS)			;SIZE NEG ⊃ IN USE
	ADDI	THIS,2			;USER DOESN'T SEE THIS HEADER
IFN DEBCOR,<
	SKIPE	PRTCOR
	PUSHJ	P,CORPRT
>
	POPJ	P,			;HERE'S YOUR BLOCK!

EXPAND:	SKIPE	XPAND(USER)		;IS IT ALLOWED TO EXPAND?
	 JRST	 GETRST			; NO, ERROR RETURN
	PUSH	P,SIZ			;SAVE TOTAL SIZE
	HRRZ	THIS,TOP(USER)		;THIS→NEW BLOCK IF NEXT LOWER IS USED
	SKIPGE	-1(THIS)		;IS TOP BLOCK FREE?
	 JRST	 GETMOR			; NO, USE WHAT YOU HAVE
	HRRZ	THIS,-1(THIS)		;UNLINK THE
	PUSHJ	P,UNLINK		; TOP BLOCK

GETMOR:	MOVE	TEMP,THIS
	ADDI	TEMP,=1024(SIZ)		;GET MORE AND THEN SOME
	POP	P,SIZ			;GET THIS BACK BEFORE YOU FORGET
GLOB <
	CAIN	USER,GLUSER		;THIS IS HOW WE TELL
	JRST	[CALLI TEMP,CORE2UUO	;GET SOME CORE
		 JRST  GETRST		;HE SPAT UPON OUR HUMBLE REQUEST.
		 PUSHJ	P,NEWB2		;LINK IT UP
		 JRST  .+4]
>;GLOB
	CALL6	(TEMP,CORE)		;ASK FOR MORE
	 JRST	 GETRST			;CAN'T GET IT
	PUSHJ	P,NEWBLK		;MAKE TOP LOOK LIKE FREE BLOCK
	CAMLE	SIZ,1(THIS)		;NOW SHOULD FIT
	 ERR	 <DRYROT -- EXPAND CODE GLUBBED UP>
	JRST	GETCOR			;GO GET BLOCK

GETRST:	
GLOB <
	PUSHJ	P,BUFRST		;RESTORE ACCUMULATORS.
	CAIN	USER,GLUSER		;WAS IT CORE2?
	SOS	CORLOK			;YES -- BACK UP COUNT.
	MOVE	USER,GOGTAB		;RESET IT TO USUAL.
	POPJ	P,			;
>;GLOB
	 JRST BUFRST
SUBTTL	 CORINC, CANINC

DSCR CORINC 
CAL PUSHJ
PAR AC B -- Addr of block to be incremented
 AC C -- amount if increase desired
RES SUCCESS: skip-return, extra core has been granted
 FAILURE: no-skip
SID none
⊗

↑↑CORINC:	
IFN DEBCOR,<
	SKIPE	PRTCOR
	 TERPRI	 <CORINC:>
>
	PUSHJ	P,JUSTSAVE		;SAVE ACS
	MOVNI	FF,1			;WANT TO DO IT
	JRST	INCR

DSCR CANINC
CAL PUSHJ
PAR same as CORINC
RES No extra core is ever actually obtained
 if entire request can be granted, skip-return
 if some extra words available, no-skip, C contains possible increment
 if no extra words available, no-skip, C contains 0
SID none except as described above
⊗

↑↑CANINC:
IFN DEBCOR,<
	SKIPE	PRTCOR
	 TERPRI	 <CANINC: >
>
	PUSHJ	P,BUFSAV
	MOVEI	FF,0			;JUST WANT TO SEE IF IT'S POSSIBLE

; IF BLOCK IS AT TOP, CAN ALWAYS DO IT

INCR:	SUBI	THIS,2			;POINT AT REAL BLOCK HEAD
GLOB <
	TRNE	THIS,400000		;CHECK TO SEE IF CORE2
	ERR	<NO CANINC SECOND SEGMENT SPACE>
>;GLOB
	HRRZ	LAST,THIS		;CHECK AT TOP
	SUB	LAST,1(THIS)		; ADDR OF END (SIZE IS NEG)
	CAMGE	LAST,TOP(USER)		;TOP BLOCK?
	 JRST	 MIDDLE		; NO
	JUMPE	FF,YESINC		;SUCCESS
	MOVNS	1(THIS)			;MAKE IT LOOK FREE
	ADD	SIZ,1(THIS)		;TOTAL SIZE
	HRRZS	-1(LAST)		;MAKE END LOOK FREE
	JRST	EXPAND			;EXPAND AND RETURN

MIDDLE:	SKIPGE	TEMP,1(LAST)		;NEXT BLOCK FREE?
	 JRST	 NONEATALL		; NO, FAILURE
	SUBI	TEMP,3			;AVAILABLE SIZE
	CAMLE	SIZ,TEMP		;IS THERE ENOUGH?
	 JRST	 MAYBE			; NO, FAILURE MAYBE

	JUMPE	FF,YESINC		;ALL OK, CAN DO, REPORT IT
CRXXB:	MOVNS	TEMP,1(THIS)		;MAKE IT LOOK FREE
	PUSH	P,(THIS)		;WILL RESTORE THIS IN CASE SOMEONE USED
	PUSH	P,THIS			;SAVE SIZE
	PUSH	P,SIZ			;AND POINTER
	ADDM	TEMP,(P)		;TOTAL SIZE DESIRED AFTER RETURN
	MOVE	SIZ,TEMP		;SIZE OF CURRENT "THIS"
	HRRZ	THIS,LAST		;MERGE "THIS" WITH "LAST"
	PUSHJ	P,UNLINK		;TAKE IT OFF FRELST
	ADD	LAST,1(THIS)		;AND INCREASE
	ADD	SIZ,1(THIS)
	MOVE	THIS,-1(P)		;RETRIEVE CURRENT BLOCK.
	PUSHJ	P,RELINK		;AND NOW RELINK ON FRELST.
	POP	P,SIZ
	POP	P,THIS
	PUSHJ	P,GETCOR		;GET THE BLOCK AGAIN, ONLY BIGGER
	 ERR	 <DRYROT>		;CAN'T HAPPEN
	POP	P,-2(THIS)		;GET POINTER WORD BACK
	AOS	(P)			;SUCCESS
	POPJ	P,			;BUFRST DONE BY GETCOR

YESINC:	AOS	(P)			;REPORT SUCCESS
IFN DEBCOR,<
	SKIPE	PRTCOR
	PUSHJ	P,CORPRT
>
	JRST	BUFRST

MAYBE:	ADDI	TEMP,3(LAST)		;GET TOP OF NEXT BLOCK AND SEE
	CAMGE	TEMP,TOP(USER)		;IF IT IS THE TOP ONE.
	 JRST	 NOTENUF		;NO  -- FAIL UTTERLY.
	JUMPE	FF,YESINC		;GOT IT IF ONLY GOING TO HERE.
	PUSH	P,SIZ			;SAVE AMOUNT REQUESTED.
	MOVEI	SIZ,-3(TEMP)		;THIS IS THE SIZE OF THE BLOCK WE
	SUB	SIZ,LAST		;KNOW WE CAN GET.
	MOVN	TEMP,SIZ
	ADDM	TEMP,(P)		;(P) NOW HAS EXTRA REQUIRED.
	PUSHJ	P,CRXXB			;AND WE DO SOO
	 ERR	<DRYROT>		; CAN'T HAPPEN.
	POP	P,SIZ			;RETRIEVE SIZE.
	MOVNI	FF,1			;SINCE CRXXB DESTROYED IT.
	JRST	INCR			;AND GO THROUGH AGAIN
					;THIS TIME IT WILL BE THE TOP BLOCK.


NOTENUF:
	SUBI	TEMP,3(LAST)		;UNDO WHAT WAS DONE ABOVE
	SKIPA	SIZ,TEMP		;CAN'T DO ALL, BUT CAN DO THIS MUCH

NONEATALL:
	MOVEI	SIZ,0			;CAN'T DO ANYTHING
	MOVEM	SIZ,BUFACS+SIZ(USER)
	JRST	BUFRST

SUBTTL	 CORREL

DSCR CORREL
CAL PUSHJ
PAR addr of block to be released in B
RES block is released to free storage
SID none
DES the block is merged with any adjoining free blocks
⊗

↑↑CORREL:
IFN DEBCOR,<
	SKIPE	PRTCOR
	 TERPRI	 <CORREL: >
>
	SKIPN	USER,GOGTAB		;MUST BE SET UP HERE
	 ERR	 <DRYROT -- CORREL CALLED WITH INITIALIZED WORLD>
GLOB <
	TRNN	THIS,400000		;IS IT SECOND SEGMENT ADDRESS?
	JRST	NOSGR			;NO
	MOVEI	USER,GLUSER		;USE THIS ONE.
	AOSE	CORLOK			;SEE IF WE CAN GET IN.
	JRST	[SOS CORLOK
		 PUSHJ	P,WAITQQ
		 JRST .-1]
NOSGR:
>;GLOB
	PUSHJ	P,JUSTSAVE		;SAVE ACS

; MERGE WITH LOWER NEIGHBOR (ADDRESS-WISE) IF POSSIBLE

	SUBI	THIS,2			;USER THINKS IT STARTED 2 PAST
	MOVN	SIZ,1(THIS)		;SIZE OF THIS BLOCK
	MOVE	LAST,SIZ		;ADDRESS OF UPPER
	ADD	LAST,THIS		;  NEIGHBOR

	CAMGE	THIS,LOWC(USER)		;IS ADDRESS IN RANGE?
	 ERR	 <DRYROT -- BAD ADDRESS TO CORREL>
	CAME	THIS,LOWC(USER)		;CAN THERE BE A LOWER BLOCK
	SKIPGE	-1(THIS)		; AND IF SO, IS IT FREE?
	 JRST	 UPPET			; NO, LOOK FOR UPPER BLOCK

	HRRZ	THIS,-1(THIS)		;→LOWER BLOCK
	PUSHJ	P,UNLINK		;UNLINK IT FROM LIST
	ADD	SIZ,1(THIS)		;INCREASE SIZE
	
; MERGE WITH UPPER NEIGHBOR IF POSSIBLE

UPPET:	CAMLE	LAST,TOP(USER)
	 ERR	 <YOU ARE ABOUT TO GET AN ILL MEM-REF>,1

	CAME	LAST,TOP(USER)		;IS THERE AN UPPER BLOCK?
	SKIPGE	1(LAST)			;AND IF SO, IS IT FREE?
	 JRST	 LNKRET			; NO, RELINK AND GO AWAY

UPPR:	PUSH	P,THIS
	HRRZ	THIS,LAST		;THIS → UPPER NEIGHBOR
	PUSHJ	P,UNLINK			;GET IT OUT
	ADD	LAST,1(THIS)		; INCREASE EXTENT
	ADD	SIZ,1(THIS)		; AND TOTAL SIZE
	POP	P,THIS			; GET HEADER POINTER BACK
LNKRET:	
GLOB <
	CAIN	USER,GLUSER
	JRST	LNKRT		;IF SEC SEGMENT, NEVER SHRINK
>;GLOB
;;#IC# 7-3-72 DCS (1-1) ADD NEW MEANING TO NOSHRK(USER)
	SKIPL	TEMP,NOSHRK(USER)	;If NOSHRK(USER) is:
	CAMG	LAST,JOBREL		;  <0, CORREL should not reduce core;
	 JRST	 LNKRT			;  >0, its RH indicates the amount of
	JUMPN	TEMP,.+2		;      free space which should be
	 MOVEI	 TEMP,=2046		;      protected from release;
	HRRZS	TEMP			;  =0, at least 2K should be protected.
	CAIGE	TEMP,4			;Only the first and third alternatives
	 MOVEI	 TEMP,4			;  were previously available.
	CAMGE	SIZ,TEMP		;Don't bother if there is already
	 JRST	 LNKRT			;  less free space available than
	ADDI	TEMP,(THIS)		;  desired
;;#IC# (1-1)
	CALL6	(TEMP,CORE)
	 ERR	 <DRYROT --CORSER&LNKRET>
	MOVE	LAST,JOBREL	; AND  2) ADJUST BLOCK TO INDICATE
	ADDI	LAST,1
	MOVEM	LAST,TOP(USER)		;AND RECORD NEW RESULTS.
	MOVE	SIZ,LAST	;          THE CHANGE BEFORE RELINKING
	SUB	SIZ,THIS
LNKRT:
	PUSHJ	P,RELINK		;PUT IT BACK
IFN DEBCOR,<
	SKIPE	PRTCOR
	PUSHJ	P,CORPRT
>
	JRST	GETRST			;AND GO AWAY

SUBTTL	 CORPRT, CORBIG

IFN DEBCOR,<
↑CORPRT:
	SETZM	TOTFRE#			;TOTAL FREE STORAGE COUNT
	TERPRI	<FREE STORAGE: >
	PUSH	P,LPSA
	MOVE	USER,GOGTAB		;THIS STUFF IS DEBUGGING
	MOVEI	LPSA,FRELST(USER)	;JUNK FOR CORGET AND FRIENDS

CPLUP:	HRRZ	LPSA,(LPSA)		;IT SHOULD BE INTUITIVELY
	JUMPE	LPSA,DUNNN		;OBVIOUS
	PRINT	<START = >
	OCTPNT	LPSA
	MOVE	TEMP,1(LPSA)
	ADDM	TEMP,TOTFRE
	PRINT	<  SIZE =  >
	OCTPNT	TEMP
	ADD	TEMP,LPSA
	PRINT	<  END =  >
	OCTPNT	TEMP
	TERPRI
	JRST	CPLUP

DUNNN:
	PRINT	<TOTAL FREE SIZE = >
	OCTPNT	TOTFRE
	SETOM	PRTCOR
	TERPRI
	CAMLE	THIS,JOBREL
	JRST	DUNMOR
	TERPRI	<THIS BLOCK: >
	PRINT	<"THIS" = >
	MOVE	TEMP,THIS
	OCTPNT	TEMP
	PRINT	<  C-SIZE = >
	HRRZ	TEMP,SIZ
	OCTPNT	TEMP
	CAML	THIS,JOBREL
	JRST	DUNMOR
	HRREI	LPSA,-2(THIS)
	JUMPLE	LPSA,DUNMOR
	PRINT	<  BLOCK-SIZE = >
	MOVN	TEMP,1(LPSA)
	OCTPNT	TEMP

DUNMOR:	TERPRI
	POP	P,LPSA
	TTCALL	11,
	TTCALL	TEMP
	TERPRI
	POPJ	P,

>

DSCR CORBIG
CAL PUSHJ
PAR NONE
RES LARGEST AVAILABLE BLOCK IN SIZ (3,C)
SID THIS (2,B) MUNGED
⊗

↑↑CORBIG: SKIPN	USER,GOGTAB
	ERR	<CORBIG: INITIALIZED WORLD>
	MOVEI	SIZ,0	;"ZERO-LENGTH" BLOCK
	MOVEI	THIS,FRELST(USER)
BIGLUP:	HRRZ	THIS,(THIS)
	JUMPE	THIS,BIGDUN	;END OF FREELIST?
	CAMGE	SIZ,1(THIS)
	MOVE	SIZ,1(THIS)	;FIND MAX
	JRST	BIGLUP
BIGDUN:	SUBI	SIZ,3		;WHAT HE SEES
	POPJ	P,



Comment  ⊗ No other core routines should be necessary to provide
	gross control over allocation.  Programs obtaining
	space from CORGET can carve the blocks up if necessary.
	Please put your core back when you're done with it.

					Thank You,
					The Management

⊗
>;NOLOW
ENDCOM (COR)
IFN ALWAYS,<
BEND CORSER
>

COMPIL(SGC,<STRNGC,STRGC,STCLER,SGINS,SGREM,%SPGC1,%ARSR1>
	   ,<GOGTAB,X11,CORGET,CORREL,CORINC,X22,CORBIG,SPRPDA>
	   ,<STRING GARBAGE COLLECTOR ROUTINES>
	   ,<%SPGC,%STRMRK,%ARRSRT>)
;String Garbage Collector Routines 

NOLOW <			;INCLUDE IN UPPER SEGMENT.

BKSZ←←=25  BKOFF←←=23 MLT←←5


↑.CORERR:
↑CORERR:
	ERR	<NO CORE FOR ALLOCATION>

DSCR STRGC(# chars desired);
CAL SAIL 
RES calls string garbage collector with #chars in -1(p)..i.e.a formal param.
⊗

HERE (STRGC)
	EXCH	A,-1(P)		;THE DESIRED A IS HERE
	MOVE	USER,GOGTAB
	MOVEM	RF,RACS+RF(USER);SAVE F REGISTER WHERE GC CAN FIND.
	PUSHJ	P,STRNGC	;COLLECT TRASH
	SUB	P,X22		;BACK UP STACK
	MOVNS	A
	ADDM	A,REMCHR(USER)
	MOVE	A,1(P)		;GET ORIGINAL "A" BACK
	JRST	2,@2(P)		;RETURN



DSCR STRNGC
CAL PUSHJ
PAR A -- number of new characters needed
 REMCHR(USER) -- has been updated by that number of chars
RES String space is compacted, new REMCHR is updated by C(A).
 Restarts if not enough room left
SID none
DES STRNGC is a two-pass process. In the first, all string descriptors
 are found and sorted into ascending sequence with respect to the locations
 of their respective texts.  String descriptors are found via the generating
 routines, described in CALSG. 
 	In the second pass, all string texts are moved down to fill any
 unused space. All descriptors are adjusted to reflect the new locations.
⊗

↑STRNGC: MOVE	USER,GOGTAB	;GET USER TABLE POINTER

	MOVEM	12,SGACS+12(USER)
	MOVEI	12,SGACS(USER)
	BLT	12,SGACS+11(USER)

;              →→→→→→ OBTAIN SPACE, INITIALIZE GARBAGE COLLECTOR ←←←←←←

	HRRZ	TEMP,TOPBYTE(USER) ;MAKE SURE DIDN'T OVERFLOW

; **** BUG TRAP
	CAMG	TEMP,STTOP(USER)
	CAMGE	TEMP,ST(USER)
	 ERR	 <DRYROT AT STRNGC>
; **** EBT

	SUB	TEMP,ST(USER)	;CREATE A DIVISOR FOR DISTRIBUTION
	ADDI	TEMP,5		; OF DESCRIPTORS DURING SGSORT
	MOVEM	TEMP,INKY(USER)
	SKIPE	XPAND(USER)	;ALLOWED TO EXPAND?
	 JRST	 INSIDE		; NO
	SETOM	ATTOP(USER)	;WANT BLOCK OFF THE TOP FOR SAFETY
	MOVEI	C,=400		;REASONABLE SIZE
	PUSHJ	P,CORGET	;IF CAN'T GET IT, TROUBLE
	SKIPA			;TRY TO GET WHAT YOU CAN
	JRST	CORROK		;GOT IT
INSIDE:	SETZM	ATTOP(USER)	;CAN'T EXPAND
	PUSHJ	P,CORBIG	;HOW MUCH CAN WE HAVE?
	PUSHJ	P,CORGET	;GET THAT AMOUNT
	ERR	<DRYROT - STRNGC CAN'T GET CORE>
CORROK:	SETZM	ATTOP(USER)	;NOW CAN GET ANYWHERE
	MOVEM	B,STBUCK(USER)	;SAVE → TO BLOCK
	SETZM	(B)
	HRLS	B
	ADDI	B,1
	MOVEI	TEMP,BKOFF(B)
	BLT	B,(TEMP)
	MOVE	B,STBUCK(USER)
	ADDI	B,BKSZ		;FIRST BKSZ WORDS IS "BUCKET" LIST
	MOVNI	C,-BKSZ(C)
	JUMPGE	C,CORERR	;BAD THING
	HRL	B,C
	SUB	B,X11		;IOWD FOR WORD ALLOC IN STRNGC
	MOVEM	B,SGFRE(USER)	;FREE SPACE POINTER

	HRRZ	A,ST(USER)
	HRLI	A,(<POINT 7,0>)
	MOVEM	A,TOPBYTE(USER)		;FIRST(USER) NEW OK POSITION
	SETZM	NUMCHR(USER)		;TOTAL # CHARS PREVIOUSLY MOVED

;		→→→→→→  SORT THE STRINGS ←←←←←←←←←
DSCR CALSG
PAR linked list of routine addresses based at SGROUT(USER)
RES each routine in list is called to provide string descriptors
 to the sorting routine, SGSORT.
SID SGSORT uses B,C,D,E,TEMP, accepts input in A. Generating
 routines may use A-T1 (12) and TEMP for their own devices.
 Q1 through T1 will not be changed by calls on SGSORT.
DES Each generating routine should do the following:
 1) Place a string descriptor in A
 2) PUSHJ P,SGSORT or PUSHJ P,@-1(P) (addr provided on stack)
 3) Repeat the process if it knows about more strings, else return
 4) Return with a POPJ (and a flourish)

The `standard' generating routines are:
 SPSG -- collects the string stack
 STRMRK -- collects string variables linked through SGLINK(USER)
 ARRMRK -- collects string arrays found in ARRPDL
 RINGSORT -- collects PNAMES from semantic blocks in compiler
 DEFSRT -- collects saved input strings during macro recursion in compiller
These routines should provide sufficient examples.

⊗


CALSG:	MOVEI	T,SGROUT(USER)		;GET LINKED LIST OF ROUTINE NAMES
	PUSH	P,T			;SAVE FIRST POINTER
	PUSH	P,[SGSORT]		;PROVIDE ACCESS TO SORTING ROUTINE
↑CALSGL:
	SKIPN	T,@-1(P)		;GO DOWN LIST UNTIL DONE
	JRST	ALLCOL			;DONE
	HRRZM	T,-1(P)			;SAVE NEW POINTER
	PUSHJ	P,@-1(T)		;CALL GENERATOR ROUTINE
	JRST	CALSGL			;DO MORE THAN ONCE


;	     →→→→→→ SORT THE SP STACK ←←←←←←

HERE(%SPGC)	HRRZ	A,SPDL(USER)	;START AT BASE OF STACK
↑%SPGC1:ADDI	A,1
	JRST	SGTST		;AND WORK UP TO CURRENT POINTER
STRNGSTACKMARKLOOP:
	PUSHJ	P,SGSORT	;SORT IT INTO LIST
SGTST:
	CAIGE	A,(SP)		;DONE?
	 JRST	 STRNGSTACKMARKLOOP ;NO
GPOPJ:	POPJ	P,		;YES, GO ON TO NEXT TYPE

;      →→→→→→ SAIL COMPILER SPECIAL SORTERS ARE IN COMSER ←←←←←

; 	         →→→→→→ SORT THE VARIABLES ←←←←←←

HERE (%STRMRK)
	SKIPN	T,STRLNK(USER)	;GET LINK
	 POPJ	 P,		; NO STRINGS AT ALL
STMKL1:	HRRZ	A,-1(T)		;→1ST STRING
	HLRZ	Q2,-1(T)	;# STRINGS THIS PROC
	JRST	SOJLP		;GO LOOP
STMKLP:	
;	SKIPN	-2(T)		;PROCEDURE ACTIVE?
;	 SETZM	 (A)		; NO, MAKE NULL STRINGS

Comment ⊗ Due to certain social pressures (WFW LIVES ON)
	strings in inactive blocks remain over garbage collection  ⊗

	PUSHJ	P,SGSORT	;SORT VARIABLES INTO LIST
SOJLP:	SOJGE	Q2,STMKLP	;SORT UNTIL DONE WITH THIS PROC (SGSORT INCRS A)

STRMK4:	HRRZ	T,(T)		;NEXT PROCEDURE
	JUMPN	T,STMKL1	; IF THERE IS ONE
	POPJ	P,		;DONE


COMMENT ⊗
		→→→→→→  SORT STRING ARRAYS ←←←←←←


	THIS ROUTINE TRIPS DOWN THE DYNAMIC LINKS, LOOKING INTO
	PROCEDURE DESCRIPTORS FOR STRING ARRAYS WHICH MIGHT HAVE BEEN ALLOCATED.
	THEN IT LOOKS FOR ANY ARRAYS OWNED BY LEAP.  THE FIRST
	WORD OF EACH ARRAY BLOCK IS THE NUMBER OF DIMENSIONS IF THE
	ARRAY IS A STRING ARRAY. THE WORD JUST PREVIOUS TO IT IS THE
	(NEGATIVE) SIZE OF THE ARRAY.
⊗

INTERNAL %ARRSRT
HERE (%ARRSRT)
	HRRZ	RF,RACS+RF(USER);REAL RF WITH LH= 0
↑%ARSR1:
PROCDO:	HLRZ	Q1,1(RF)	;FETCH PDA
	CAIN	Q1,SPRPDA	;IS IT SPROUTER??
	POPJ	P,		;YES
	MOVE	Q1,PD.LLW(Q1)	;WE HAVE TO DO SOMETHING -- PT AT LVI
CHK:	SKIPN	T,(Q1)		;GET ENTRY
	JRST	GODOWN		;0 MEANS OF PROC DESCR
;;#HI#↓ 5-15-72 DCS WAS TESTING 200000 (TYPE 4?) BIT, WRONG BIT!
	TLC	T,100000	;TYPE 2? (STRING ARRAY)
	TLNE	T,740000	;
	AOJA	Q1,CHK		;NO
	SKIPN	A,@T		;THERE??
	AOJA	Q1,CHK		;NO
;;#  # 5-3-72 DCS
	SUBI	A,1		;A→2D WORD, FIRST ENTRY -- DCS 5-3-72
;;#  #
	SKIPL	Q2,-1(A)	;BETTER BE THERE
	ERR	<DRYROT AT ARRSRT>
	PUSHJ	P,ARPUTX	;GO SORT IT
	AOJA	Q1,CHK

GODOWN:	HRRZ	RF,(RF)		;NOTE THAT RESTR WILL PUT RF BACK
	CAIE	RF,-1		;
	JRST	PROCDO 		;-1 WILL SAY END


LARR:	SKIPN	T1,ARYLS(USER)	;LEAPING LISTS
	POPJ	P,		;NONE
LAR1:	
	HLRZ	Q2,(T1)		;GET ADDRESS
;;#  # 5-3-72 DCS SET UP A
	MOVEI	A,-1(Q2)	;A→1ST WORD, FIRST ENTRY
;;#  #
	SKIPL	Q2,-2(Q2)		;BE SURE
	ERR	<LEAPING DRYROT AT ARRSRT>
	PUSHJ	P,ARPUTX	;GO SORT IT

LAR2:	HRRZ	T1,(T1)		;MERRILY WE LINK ALONG
	JUMPN	T1,LAR1		;
	POPJ	P,		;HOME AT LAST

ARPUTX:	
	HRRZS	Q2		;YES, GET TOTAL SIZE
	LSH	Q2,-1		;NUMBER OF STRINGS

	JRST	ARSLP


ARS3:	
	 PUSHJ	 P,SGSORT	; BUT COLLECT NON-CONSTANTS 
ARSLP:	SOJGE	Q2,ARS3		;A INCREMENTED IN SGSORT, LOOP UNTIL DONE
	POPJ	P,		;ALL DONE WITH THIS ARRAY.

;  SUBROUTINE ENTERED WITH A → A STRING DESCRIPTOR.  CONVERTS
;  IT TO GARBAGE COLLECTOR FORMAT.  USES B, C.D,E,TEMP
;  START CONTAINS FIRST #CHARS FOR BEGINNING OF STRING SPACE.
; WARNING ***** CLOBBERS B,C,D,E,TEMX  **********

SGSORT:	

	HLLZ	B,(A)		;GET STRING NUMBER
	JUMPE	B,SGSRT		; DON'T COLLECT CONSTANTS OR NULL STRINGS

	HRRZ	D,1(A)		;MAKE SURE STRING IN RANGE
	HRRE	C,(A)		;CHECK LENGTH CONSISTENCY

; *** BUG TRAP
	JUMPE	C,DONBUG 	;DON'T WORRY MUCH ABOUT NULL STRINGS
	JUMPL	C,BUGG
	CAMG	D,STTOP(USER)
	CAMGE	D,ST(USER)
BUGG:	 ERR	 <DRYROT AT SGSORT>,1
DONBUG:
; *** EBT

	HLLZ	B,1(A)		;GET POINTER AND SIZE FIELDS OF BP
	HRRI	B,[BYTE (7) 0,1,2,3,4,5]
	ILDB	B,B		;#CHARS REPRESENTED BY POINTER
				;C HAS ADDR FILED OF BP (SEE ABOVE)
	SUB	D,ST(USER)		; - STRING SPACE BASE
	IMULI	D,5		;#CHARS
	ADD	B,D		; + CHARS IN POINTER
	MOVEM	B,1(A)		; TO BP WORD
	ADD	C,B		; + #CHARS FIELD (D LOADED ABOVE)
	HRRZM	C,(A)		;TO #CHARS WORD
	MOVE	D,B		;NOW DISTRIBUTE STRING TO PROPER
	IMULI	D,MLT		; LIST TO SPEED SORT
	IDIV	D,INKY(USER)	; SEE ABOVE FOR INKY CALC
	ADD	D,STBUCK(USER)	;D→PROPER "BUCKET" ENTRY

; *** BUG TRAP
	MOVE	TEMP,STBUCK(USER)
	CAML	D,TEMP
	CAIL	D,BKSZ(TEMP)
	 ERR	 <DRYROT AT SGSLUP>,1
; *** EBT


;  A→ STRING DESCRIPTOR (MARKED)  -- D→BUCKET LIST THIS STRING
;  B IS START COUNT [=1(A)] -- C IS END COUNT [=(A)]

SGSLUP:	MOVE	E,D		;E←CDR(E), IN FACT
	HRRZ	D,(E)		;D←CDR(E)
	SKIPN	D		;DONE?
	JRST	INSERT		; YES, INSERT AT END
	HLRZ	TEMP,(D)	;TEMP←CAR(D)
	CAMGE	B,1(TEMP)	;NEW START LESS?
	JRST	INSERT		;YES, INSERT THIS ONE IN FRONT OF IT
	CAME	B,1(TEMP)	;NEW START SAME?
	JRST	SGSLUP		;NO, GREATER

; EQUAL START COUNTS, ARRANGE BY END COUNT, DESCENDING SEQUENCE

	CAMG	C,(TEMP)	;NEW END GT OLD?
	JRST	SGSLUP		;NO, CONTINUE
;	(JRST	INSERT)		;YES

INSERT:
	MOVE	TEMP,SGFRE(USER)
	AOBJN	TEMP,STILMOR	;EXPAND LINK SPACE
SGXPND:	
	PUSH	P,TEMP
	MOVE	B,STBUCK(USER)	;→CURRENT FWS BLOCK
	MOVEI	C,=100		;GET 100 MORE
	PUSHJ	P,CORINC	;EXPAND THE BLOCK
	 ERR	<NO CORE FOR ALLOCATION>
	POP	P,TEMP
	SUB	TEMP,[(100)]	;THERE IS MORE

STILMOR:
	MOVEM	TEMP,SGFRE(USER)
	HRLM	A,(TEMP)
	HRRM	D,(TEMP)
	HRRM	TEMP,(E)
SGSRT:	ADDI	A,2		;AUTO-INDEXING
	POPJ	P,

;  FIND A DISJOINT STRING GROUP, MOVE IT BACK.
;  MARK POINTERS APPROPRIATELY.

ALLCOL:	SUB	P,X22		;REMOVE JUNK PUT ON BY CALSG

SGSWEP:
	SETZB	T,T1		;IN CASE NO STRINGS AT ALL
	MOVEI	Q2,1		;INIT STRING NO.
	MOVE	Q3,STBUCK(USER) ;WORK UP BUCKET LIST, HANDLING
	MOVEI	FF,BKSZ(Q3)	;EVERYTHING IN THE PATH
	SUBI	Q3,1
	PUSHJ	P,FSTSTR	;A→FIRST LIST
	HLRZ	Q1,(A)		;Q1 → FIRST MARKED DESCRIPTOR
	JRST	SGFX1		;JUMP INTO THINGS

SGFIX:	PUSHJ	P,NXTSTR	;A→NEXT LIST ELEMENT
	HLRZ	Q1,(A)		;Q1 → NEXT DESCRIPTOR
	CAMG	T1,1(Q1)	;INCLUDED IN OR OVERLAPPING THIS STRING
	 JRST	 SGBLT		; NO, MOVE OLD BEFORE HANDLING NEW
	PUSHJ	P,FIXPTR	;FIX UP DESCRIPTOR
	CAMGE	T1,TEMP		;OVERLAPPING STRING
	 MOVE	 T1,TEMP	; YES, USE BIGGER END POINT
	JRST	SGFIX		;CONTINUE

SGBLT:	ADDI	Q2,1		;INCREMENT STRING NUMBER
	MOVN	B,T
	ADD	B,T1		;TOTAL STRING SIZE
	SKIPN	SGLIGN(USER)	;HAVE TO ALIGN TO FW BDRY?
	 JRST	 NOLIGN		; NO
	ADDI	B,4		;YES, DO IT
	IDIVI	B,5
	IMULI	B,5		;NOW MULT OF 5 CHARS, BIG ENOUGH
NOLIGN:
	ADDM	B,NUMCHR(USER)	;NUMBER USED SO FAR
	MOVE	C,T		;STARTING COUNT FOR STRING
	PUSHJ	P,MKBPT		;PICK UP FROM HERE
	MOVE	T,TOPBYTE(USER) ;PUT DOWN HERE
	JUMPE	B,SGBLT1	;DON'T DO IT IF NOT NECESSARY
BLTLUP:	ILDB	D,C
	IDPB	D,T		;WHEEE!
	SOJG	B,BLTLUP	;MOVE 'EM ON OUT
	MOVEM	T,TOPBYTE(USER)	;RESTORE IT

SGBLT1:	JUMPE	A,STSTAT	;LAST ONE
SGFX1:	MOVE	T,1(Q1)		;INITIALIZE START OF STRING,
	MOVE	T1,(Q1)		; END OF STRING,
	MOVE	E,T		; OFFSET FOR BP FIXUPS
	SUB	E,NUMCHR(USER)	; (THIS IS THE OFFSET)
	PUSHJ	P,FIXPTR	;FIX UP THIS DESCRIPTOR
	JRST	SGFIX		;CONTINUE

NXTSTR:	HRRZ	A,(A)		;A←CDR(A)
	JUMPN	A,APOPJ		; GOT ONE, DONE
FSTSTR:	AOS	A,Q3		;END OF THAT LIST, LOOK AT NEXT
	CAMGE	A,FF		;OOOPS, THERE ARE NO MORE!
	 JRST	 NXTSTR		; YES THERE ARE
	SUB	P,X11		;DON'T RETURN, BUT MARK DONE,
	MOVEI	A,0		; AND GO OFF FOR LAST 
	JRST	SGBLT		; NOSTALGIC MOVE

FIXPTR:	MOVE	TEMP,(Q1)
	SUB	TEMP,1(Q1)		;SIZE OF STRING FOR THIS DESCRIPTOR
	HRL	TEMP,Q2		;ADD STRING NUMBER
	EXCH	TEMP,(Q1)		;PUT FIRST WORD AWAY
	MOVE	C,1(Q1)		;START COUNT
	SUB	C,E		;ADJUST TO NEW LOCATION
	PUSHJ	P,MKBPT		;MAKE A BYTE POINTER
	MOVEM	C,1(Q1)		;THIS BABY IS READY TO FLY!
APOPJ:	POPJ	P,		;ALL DONE

; MKBPT TAKES A #CHARS IN C, MAKES A BYTE POINTER RELATIVE TO ST
; OUT OF IT, LEAVES IT IN C -- DESTROYS D

MKBPT:	IDIVI	C,5		;WORD # IN C, CHAR OFLOW IN D
	ADD	C,ST(USER)		;REAL WORD #
	HLL	C,[POINT 7,0
		   POINT 7,0,6
		   POINT 7,0,13
		   POINT 7,0,20
		   POINT 7,0,27](D)  ;POINTER PART
	POPJ	P,

; FINISH UP

STSTAT:	
	SKIPN	SGLIGN(USER)	;HAVE TO LINE UP TOPBYTE?
	 JRST	 NORCLR		;NO
	MOVE	C,T1		;END CHAR # OF LAST STRING
	SUB	C,E		;ADJUST BY THE WINNING OFFSET
	PUSHJ	P,MKBPT		;MAKE A BP FOR TO BE TOPBYTE
	MOVEM	C,TOPBYTE(USER)	;FOR THE RIDICULOUS, DEMANDING SAIL
	PUSHJ	P,RESCLR	;CLEAR REST OF STRING SPACE
;;#GI# DCS 2-5-72 REMOVE TOPSTR
NORCLR:	AOS	SGCCNT(USER)
	MOVN	B,STMAX(USER)
	IMULI	B,5
	ADD	B,NUMCHR(USER)
;;#GI# DCS 2-2-72 (2-3) LEAVE SOME SLOP SO ONE NEEDN'T FEAR INSET
	ADDI	B,=15		;SOME SLOP
	ADD	B,SGACS+A(USER)	;#CHARS WHICH CAUSED THIS MESS IN FIRST PLACE
	MOVEM	B,REMCHR(USER)
;;#GI (2-3)
	JUMPGE	 B,[ERR (<STRING SPACE EXHAUSTED, WILL RESTART>,1)
		    JRST @JOBREN]  ;RE-ALLOCATE
	MOVE	B,STBUCK(USER)	;RELEASE IT
	PUSHJ	P,CORREL
	HRLZI	12,SGACS(USER)
	BLT	12,12
	POPJ	P,


COMMENT ⊗Sgins, Sgrem ⊗

DSCR SGINS
CAL PUSHJ
PAR PUSH P,[routine name]
 PUSH P,[addr of 2-word block]
RES block is used to place routine in the list of descriptor generators
 for CALSG.
SID stack adjusted
⊗

↑↑SGINS:
	PUSH	P,-2(P)		;ADDR OF ROUTINE
	PUSHJ	P,SGREM		;NEVER LET IT BE IN TWICE
	MOVE	USER,GOGTAB
	POP	P,UUO1(USER)
	POP	P,LPSA		;→LINK BLOCK FOR NEW ROUTINE
	POP	P,-1(LPSA)	;PUT ROUTINE ADDRESS AWAY
	HRL	LPSA,SGROUT(USER);GET OLD LINK POINTER
	HLRM	LPSA,(LPSA)	;PUT IN NEW LINK POSITION
	HRRM	LPSA,SGROUT(USER);PUT NEW POINTER IN LINK HEAD
	JRST	@3(P)		;RETURN

DSCR SGREM
CAL PUSHJ
PAR PUSH P,[routine addr]
RES routine is removed from list of descriptor generators, if it was on it
⊗

↑↑SGREM:
	MOVE	USER,GOGTAB
	POP	P,UUO1(USER)
	POP	P,TEMP		;ADDR TO BE REMOVED
	MOVEI	LPSA,SGROUT(USER);HEAD OF LIST
SGRL:	MOVE	USER,LPSA	;PREV←THIS
	SKIPN	LPSA,(USER)	;THIS←(PREV)
	 JRST	 @2(P)		;DIDN'T FIND IT
	CAME	TEMP,-1(LPSA)	;IS THIS THE ROUTINE?
	 JRST	 SGRL		;NO, GET NEXT
	HRRZ	TEMP,(LPSA)	;YES, REMOVE IT FROM LIST
	HRRM	TEMP,(USER)
	JRST	@2(P)


DSCR STCLER
CAL PUSHJ
RES Clears all string variables on STRLNK(USER) to null strings
DES compiler only
⊗

↑STCLER:
	SKIPE	SGLIGN(USER)		;CLEAR REST?
	PUSHJ	P,RESCLR	;CLEAR REST OF STRING SPACE
	SKIPN	T,STRLNK(USER)	;PARALLELS STRNGC'S LOOP
	POPJ	P,		;CLOSELY
	PUSH	P,B		;JUST IN CASE
	HRLZI	B,-1		;FOR TESTING STRING NO.
STC1:	HRRZ	A,-1(T)
	HLRZ	Q2,-1(T)
STCLLP:	SOJL	Q2,STCLD1
	TDNE	B,(A)		;DON'T COLLECT STRING CONSTANTS
	SETZM	(A)
	ADDI	A,2
	JRST	STCLLP
STCLD1:	;SETZM	-2(T)		;***** CAN'T DO THIS UNLESS PATSW IS
				; *** ON IN COMPILER!!!!!
	HRRZ	T,(T)
	JUMPN	T,STC1
	POP	P,B
	POPJ	P,

DSCR RESCLR
CAL PUSHJ 
DES Used after STRNGC. Clears remaining string space to 0 (compiler only)
⊗
RESCLR:	SKIPL	A,TOPBYTE(USER)	;CAN ZERO FIRST WORD IF 440700
	ADDI	A,1		;ELSE START AT NEXT
	SETZM	(A)
	HRLS	A
	ADDI	A,1		;BLT WORD
	MOVE	B,STTOP(USER)	;END OF STRING SPACE
	BLT	A,-1(B)		;ZERO!!
	POPJ	P,

INTERNAL BRKMSK
↑BRKMSK:	0
	FOR @& JJ←=17,0,-1 <
	<1 ⊗ (JJ+=18)> + (1 ⊗ JJ)>
>;NOLOW
ENDCOM (SGC)
IFN ALWAYS,<
NOLOW <
	↑CORGET←CORGET
>;NOLOW
>;IFN ALWAYS
SUBTTL	GOGOL
SUBTTL	Some Runtime Routines Which Could Go Nowhere Else

DSCR BEGIN GOGOL
DES RUN-TIME ROUTINES WILL BE DESCRIBED BY SAIL MANUAL CALLING SEQUENCES ONLY
⊗
NOLOW <
IFN ALWAYS,<BEGIN GOGOL>
>;NOLOW
COMPIL(KNT,<K.ZERO,K.OUT>,<GETCHAN,GOGTAB>
      ,<K.ZERO, K.OUT -- PERFORMANCE COUNTING ROUTINES>)
COMMENT ⊗ Kounter Routines⊗
DSCR K.ZERO -- Zero out counters
CAL PUSHJ  P,K.ZERO
RES The counter arrays of the sail program loaded are  set  to  zero.
K.ZERO  determines  the location of the counter blocks via the loader
link chain (5) whose head is in the location KNTLNK(USER).  If  there
are  no  counters,  the  routine  is  essentially  a  NO-OP.  SID All
registers used by K.ZERO are saved on entry and restored on exit. SEE
K.OUT
⊗

HERE(K.ZERO)
	PUSH	P,2		;SAVE REGISTER 2
	MOVE	USER,GOGTAB
	SKIPN	2,KNTLNK(USER)	;GET LINK TO COUNTERSS
	JRST	K.ZR2		;THERE ARE NONE
	PUSH	P,3		;SAVE OTHER REGS NEEDED
	PUSH	P,4
	PUSH	P,5
K.Z1:	MOVE	3,2(2)		;GET SECOND IOWD OF HEADER BLOCK
	MOVEI	4,2(3)		;GET <.KOUNT+1>
	HRLI	4,-1(4)		;GET READY FOR BLT
	HLRO	5,3		;GET -COUNT
	MOVN	5,5		;MAKE THAT +COUNT
	HRLI	5,3		;PUT AN INDEX FIELD OF 3
	SETZM	-1(4)		;ZERO THE FIRST COUNTER
	BLT	4,@5		;ZERO THE REST
	SKIPE	2,(2)		;GET THE NEXT SET OF COUNTERS
	JRST	K.Z1		;ZERO THEM
	POP	P,5		;RESTORE THE REGISTERS
	POP	P,4
	POP	P,3
K.ZR2:	POP	P,2
	POPJ	P,		;RETURN

DSCR K.OUT -- Write out counters
CAL PUSHJ P,K.OUT
RES The values of the statement counters are written out to the
 disk.  The IOWDs used to write them are also written out in
 order to be able to know how many to read back in.  The filename
 is obtained from the header block of the first program loaded.
 The data blocks have the following form:

		--------------------------
		|   SIXBIT /FILNAM/	 |
		--------------------------
		|   LINK to other blocks |
		--------------------------
		|   IOWD  1,.+1		 |
		--------------------------
		|   IOWD  n,.KOUNT	 |
		--------------------------
		|   0			 |
		--------------------------
    .KOUNT:	|   1st counter		 |
		--------------------------
		|   . . .		 |

		|   . . .		 |
		--------------------------
		|   nth counter		 |
		--------------------------

SID No registers are permanently modified.
⊗
HERE(K.OUT)
	MOVE	USER,GOGTAB
	SKIPN	KNTLNK(USER)	;ARE THERE ANY COUNTERS
	POPJ	P,		;NO


COMMENT	⊗	First save registers 0-16
⊗

	MOVEM	16,17(P)	;SAVE IN THE STACK
	MOVEI	16,1(P)		;GET READY TO STORE 0-15
	BLT	16,16(P)	;DO IT
	ADD	P,[XWD 17,17]	;ADJUST STACK POINTER
	TLNN	P,400000	;CHECK FOR OVERFLOW
	ERR	<PDL overflow in K.OUT routine>


COMMENT ⊗	Before the counters can be written out, it
	is necessary to chain the blocks together in the
	proper direction.  Recall that there will be multiple
	blocks only if the core image is the result of loading
	multiple compilatons.
⊗

	MOVE	2,KNTLNK(USER)	;GET LINK TO LAST BLOCK
	SKIPN	1,(2)		;GET LINK TO PREV.
	JRST	.+5		;THAT'S ALL
	MOVEI	0,1(2)		;GET ADDR OF 1st IOWD OF THIS BLOCK
	MOVEM	0,3(1)		;STORE BELOW 2nd IOQS OF PREV BLOCK
	MOVE	2,1		;CONTINUE
	JRST	.-5


COMMENT ⊗	At this point, 1(2) contains the start of a dump
	mode command chain that will write out all of the counters.
	-1(2) contains the filename for the counter file.
⊗

	PUSHJ	P,GETCHAN	;GET AN AVAILABLE CHANNEL
	JUMPL	1,K.OERR	;NONE AVAILABLE
	MOVE	0,[XWD K.OD1,3] ;MOVE CODE TO REGISTERS
	BLT	0,16		;SO THAT IT CAN BE SAFELY MODIFIED
	DPB	1,[POINT 4,3,12]  ;STORE CHANNEL NUMBER IN OPEN INSTR
	DPB	1,[POINT 4,5,12]  ;STORE CHANNEL NUMBER IN ENTER INSTR
	MOVE	10,-1(2)	;PICK UP FILE NAME
	JRST	3		;OPEN AND ENTER,HOPEFULLY RETURNING TO .+1
K.O1:	MOVE	0,[XWD K.OD2,3] ;DO IT AGAIN
	BLT	0,7
	DPB	1,[POINT 4,3,12]  ;OUT INSTRUCTION
	DPB	1,[POINT 4,6,12]  ;RELEAS INSTRUCTION
	JRST	3


COMMENT ⊗	The counters have been written out to the disk.  It's
	time to restore the registers and go home.
⊗

K.O2:	MOVSI	16,-16(P)	;PREPARE TO RESTORE REGS 
	BLT	16,16		; FROM THE STACK
	SUB	P,[XWD 17,17]	;ADJUST STACK POINTER
	POPJ	P,		;RETURN

K.OERR:	IOERR	<I/O error in writing counter file>


COMMENT ⊗	The following instructions are moved into 
	registers before they are executed, since the "channel"
	portion of them must be modified at run time.
⊗

K.OD1:	OPEN	0,14		;(3) OPEN DISK ON SPECIFIED CHANNEL
	JRST	K.OERR		;(4) TROUBLE
	ENTER	0,10		;(5)
	JRST	K.OERR		;(6) RIGHT HERE IN RIVER CITY
	JRST	K.O1		;(7) READY TO WRITE 'EM OUT
	0			;(10) FILLED IN WITH FILE NAME
	SIXBIT 	/KNT/		;(11) EXTENSION
	0			;(12)
	0			;(13)
	17			;(14) DUMP MODE
	SIXBIT	/DSK/		;(15) DEVICE DISK
	0			;(16) NO BUFFERS

K.OD2:	OUT	0,1(2)		;(3) WRITE OUT COUNTERS
	JRST	6		;(4) ALL OK
	JRST	K.OERR		;(5) PROBLEMS
	RELEAS	0		;(6) CLOSE FILE
	JRST	K.O2		;(7) GO BACK TO K.OUT

ENDCOM (KNT)
COMPIL(POW,<FPOW,POW>,<SAVE,RESTR,X33>,<POW, FPOW -- EXPON. ROUTINES>)

DSCR BEGIN UTILS
⊗
IFN ALWAYS,<	BEGIN	UTILS>
COMMENT % EXPONENTIATION CODE
  POW(EXP,ARGUMENT) OR
 FPOW(EXP,ARGUMENT) DEPENDING  %


DSCR POW, FPOW, LOGS, FLOGS(EXPONENT,ARGUMENT);
CAL SAIL
DES CALLS GENERATED BY COMPILER FOR ↑ OPERATOR
⊗

↑↑FPOW:	PUSHJ	P,SAVE
	JSP	B,SETEXP		;SET∧ UP, SAVE ACS
	MOVSI	B,(1.0)		;SET FOR FLOATING
	JUMPE	A,EXZERO	;0 EXPONENT

FEXLUP:	TRNE	A,1		;COLLECT PRODUCT?
	FMPR	B,C		;YES
	ASH	A,-1		;PREPARE TO LOOK AT NEXT BIT
	JUMPE	A,EXDUN		;ALL DONE IF ZERO
	FMPR	C,C		;SQUARE BASE
	JRST	FEXLUP

↑↑POW:	PUSHJ	P,SAVE
	JSP	B,SETEXP
	MOVEI	B,1
	JUMPE	A,EXZERO

EXPLUP:	TRNE	A,1
	IMUL	B,C
	ASH	A,-1
	JUMPE	A,EXDUN
	IMUL	C,C
	JRST	EXPLUP

EXZERO:	SKIPN	C		;0↑0
	ERR	<0↑0 NOT DEFINED>
EXDUN:	MOVEM	B,RACS+1(USER)
	MOVEI	LPSA,0
	JRST	RESTR

;  SET UP FOR POWER ROUTINES

SETEXP:	POP	P,UUO1(USER)	;RETURN FROM (F)EXP
	POP	P,C		;OPERAND
	POP	P,A		;EXPONENT
	SKIPGE	A		;EXP ≥0?
	ERR	<NEGATIVE EXPONENT NOT IN -- YOU LOSE>
	JRST	(B)		;RETURN
ENDCOM (POW)

NOLOW <
NOUP <
COMPIL(LOG,<LOGS,FLOGS>,<SAVE,RESTR,X33>,<LOGS & FLOGS FOR F4 LINKAGE>)

EXTERNAL EXP3.0	;FORTRAN MAGIC FOR REAL↑REAL

↑↑LOGS:	PUSHJ	P,SAVE
	FLOAT	0,-1(P)
	MOVE	1,-2(P)	;EXPONENT
	PUSHJ	P,EXP3.0
	FIX
FORGO:	MOVEM	RACS+1(USER)
	MOVE	LPSA,X33
	JRST	RESTR


↑↑FLOGS: PUSHJ	P,SAVE
	MOVE	0,-1(P)
	MOVE	1,-2(P)
	PUSHJ	P,EXP3.0
	JRST	FORGO
ENDCOM (LOG)
>;NOUP
>;NOLOW			;...


COMPIL(COD,<CODE,CALL>,<.SKIP.,CVSIX,X22,GOGTAB,X33>,<CODE, CALL>)

DSCR VAL←CODE(OCTAL COMMAND, REFERENCE ARG);
⊗
Comment ⊗CODE
   Reference arg is added to octal command.  CODAC(USER)
   is placed in AC 1.  The constructed word is executed, and AC 1 resaved.
   Isn't that clever?  (AC1 is also returned as the value of the call)
⊗

HERE (CODE)	MOVE	USER,GOGTAB
	SETOM	.SKIP.		;ASSUME IT SKIPS
	PUSH	P,0
	MOVE	1,CODAC(USER)		;GET USER'S AC
	MOVE	0,-3(P)
	ADDI	0,@-2(P)		;CALCULATE THE INSTR DO BE EXECUTED
	XCT	0			;DO IT
	SETZM	.SKIP.			;DIDN'T SKIP
	MOVEM	1,CODAC(USER)
	POP	P,0
	SUB	P,X33
	JRST	@3(P)


DSCR VALUE←CALL(VAL,"FUNCTION");
CAL SAIL
⊗

↑↑.CALL:
HERE (CALL)
	SETOM	.SKIP.		;ASSUME A SKIP
	PUSHJ	P,CVSIX		;PARSE SIXBIT
	MOVE	TEMP,A		;SIXBIT FOR WHAT'S WANTED
	MOVE	A,-1(P)		;INPUT VALUE
	CALL	A,TEMP
	SETZM	.SKIP.		;NO SKIP, RECORD IT
	SUB	P,X22		;RETURN VALUE IN 1, WANT IT OR NOT
	JRST	@2(P)

ENDCOM (COD)

IFN ALWAYS,<BEND UTILS>
SUBTTL	STRING HANDLING ROUTINES